1 /* 2 * Copyright (c) 1999, 2024, 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 java.lang.reflect; 27 28 import java.lang.invoke.MethodHandle; 29 import java.lang.invoke.MethodHandles; 30 import java.lang.invoke.MethodType; 31 import java.lang.invoke.WrongMethodTypeException; 32 import java.lang.module.ModuleDescriptor; 33 import java.util.ArrayDeque; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.Collections; 37 import java.util.Deque; 38 import java.util.HashMap; 39 import java.util.HashSet; 40 import java.util.IdentityHashMap; 41 import java.util.List; 42 import java.util.Map; 43 import java.util.Objects; 44 import java.util.Set; 45 import java.util.concurrent.ConcurrentHashMap; 46 import java.util.concurrent.atomic.AtomicInteger; 47 import java.util.concurrent.atomic.AtomicLong; 48 import java.util.function.BooleanSupplier; 49 50 import jdk.internal.access.JavaLangAccess; 51 import jdk.internal.access.SharedSecrets; 52 import jdk.internal.module.Modules; 53 import jdk.internal.misc.VM; 54 import jdk.internal.misc.CDS; 55 import jdk.internal.loader.ClassLoaderValue; 56 import jdk.internal.vm.annotation.Stable; 57 58 import static java.lang.invoke.MethodType.methodType; 59 import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC; 60 61 /** 62 * 63 * {@code Proxy} provides static methods for creating objects that act like instances 64 * of interfaces but allow for customized method invocation. 65 * To create a proxy instance for some interface {@code Foo}: 66 * <pre>{@code 67 * InvocationHandler handler = new MyInvocationHandler(...); 68 * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), 69 * new Class<?>[] { Foo.class }, 70 * handler); 71 * }</pre> 72 * 73 * <p> 74 * A <em>proxy class</em> is a class created at runtime that implements a specified 75 * list of interfaces, known as <em>proxy interfaces</em>. A <em>proxy instance</em> 76 * is an instance of a proxy class. 77 * 78 * Each proxy instance has an associated <i>invocation handler</i> 79 * object, which implements the interface {@link InvocationHandler}. 80 * A method invocation on a proxy instance through one of its proxy 81 * interfaces will be dispatched to the {@link InvocationHandler#invoke 82 * invoke} method of the instance's invocation handler, passing the proxy 83 * instance, a {@code java.lang.reflect.Method} object identifying 84 * the method that was invoked, and an array of type {@code Object} 85 * containing the arguments. The invocation handler processes the 86 * encoded method invocation as appropriate and the result that it 87 * returns will be returned as the result of the method invocation on 88 * the proxy instance. 89 * 90 * <p>A proxy class has the following properties: 91 * 92 * <ul> 93 * <li>The unqualified name of a proxy class is unspecified. The space 94 * of class names that begin with the string {@code "$Proxy"} 95 * should be, however, reserved for proxy classes. 96 * 97 * <li>The package and module in which a proxy class is defined is specified 98 * <a href="#membership">below</a>. 99 * 100 * <li>A proxy class is <em>final and non-abstract</em>. 101 * 102 * <li>A proxy class extends {@code java.lang.reflect.Proxy}. 103 * 104 * <li>A proxy class implements exactly the interfaces specified at its 105 * creation, in the same order. Invoking {@link Class#getInterfaces() getInterfaces} 106 * on its {@code Class} object will return an array containing the same 107 * list of interfaces (in the order specified at its creation), invoking 108 * {@link Class#getMethods getMethods} on its {@code Class} object will return 109 * an array of {@code Method} objects that include all of the 110 * methods in those interfaces, and invoking {@code getMethod} will 111 * find methods in the proxy interfaces as would be expected. 112 * 113 * <li>The {@link java.security.ProtectionDomain} of a proxy class 114 * is the same as that of system classes loaded by the bootstrap class 115 * loader, such as {@code java.lang.Object}. 116 * 117 * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method can be used 118 * to determine if a given class is a proxy class. 119 * </ul> 120 * 121 * <p>A proxy instance has the following properties: 122 * 123 * <ul> 124 * <li>Given a proxy instance {@code proxy} and one of the 125 * interfaces, {@code Foo}, implemented by its proxy class, the 126 * following expression will return true: 127 * <pre> 128 * {@code proxy instanceof Foo} 129 * </pre> 130 * and the following cast operation will succeed (rather than throwing 131 * a {@code ClassCastException}): 132 * <pre> 133 * {@code (Foo) proxy} 134 * </pre> 135 * 136 * <li>Each proxy instance has an associated invocation handler, the one 137 * that was passed to its constructor. The static 138 * {@link Proxy#getInvocationHandler Proxy.getInvocationHandler} method 139 * will return the invocation handler associated with the proxy instance 140 * passed as its argument. 141 * 142 * <li>An interface method invocation on a proxy instance will be 143 * encoded and dispatched to the invocation handler's {@link 144 * InvocationHandler#invoke invoke} method as described in the 145 * documentation for that method. 146 * 147 * <li>A proxy interface may define a default method or inherit 148 * a default method from its superinterface directly or indirectly. 149 * An invocation handler can invoke a default method of a proxy interface 150 * by calling {@link InvocationHandler#invokeDefault(Object, Method, Object...) 151 * InvocationHandler::invokeDefault}. 152 * 153 * <li>An invocation of the {@code hashCode}, 154 * {@code equals}, or {@code toString} methods declared in 155 * {@code java.lang.Object} on a proxy instance will be encoded and 156 * dispatched to the invocation handler's {@code invoke} method in 157 * the same manner as interface method invocations are encoded and 158 * dispatched, as described above. The declaring class of the 159 * {@code Method} object passed to {@code invoke} will be 160 * {@code java.lang.Object}. Other public methods of a proxy 161 * instance inherited from {@code java.lang.Object} are not 162 * overridden by a proxy class, so invocations of those methods behave 163 * like they do for instances of {@code java.lang.Object}. 164 * </ul> 165 * 166 * <h2><a id="membership">Package and Module Membership of Proxy Class</a></h2> 167 * 168 * The package and module to which a proxy class belongs are chosen such that 169 * the accessibility of the proxy class is in line with the accessibility of 170 * the proxy interfaces. Specifically, the package and the module membership 171 * of a proxy class defined via the 172 * {@link Proxy#getProxyClass(ClassLoader, Class[])} or 173 * {@link Proxy#newProxyInstance(ClassLoader, Class[], InvocationHandler)} 174 * methods is specified as follows: 175 * 176 * <ol> 177 * <li>If all the proxy interfaces are in <em>exported</em> or <em>open</em> 178 * packages: 179 * <ol type="a"> 180 * <li>if all the proxy interfaces are <em>public</em>, then the proxy class is 181 * <em>public</em> in an unconditionally exported but non-open package. 182 * The name of the package and the module are unspecified.</li> 183 * 184 * <li>if at least one of all the proxy interfaces is <em>non-public</em>, then 185 * the proxy class is <em>non-public</em> in the package and module of the 186 * non-public interfaces. All the non-public interfaces must be in the same 187 * package and module; otherwise, proxying them is 188 * <a href="#restrictions">not possible</a>.</li> 189 * </ol> 190 * </li> 191 * <li>If at least one proxy interface is in a package that is 192 * <em>non-exported</em> and <em>non-open</em>: 193 * <ol type="a"> 194 * <li>if all the proxy interfaces are <em>public</em>, then the proxy class is 195 * <em>public</em> in a <em>non-exported</em>, <em>non-open</em> package of 196 * <a href="#dynamicmodule"><em>dynamic module</em>.</a> 197 * The names of the package and the module are unspecified.</li> 198 * 199 * <li>if at least one of all the proxy interfaces is <em>non-public</em>, then 200 * the proxy class is <em>non-public</em> in the package and module of the 201 * non-public interfaces. All the non-public interfaces must be in the same 202 * package and module; otherwise, proxying them is 203 * <a href="#restrictions">not possible</a>.</li> 204 * </ol> 205 * </li> 206 * </ol> 207 * 208 * <p> 209 * Note that if proxy interfaces with a mix of accessibilities -- for example, 210 * an exported public interface and a non-exported non-public interface -- are 211 * proxied by the same instance, then the proxy class's accessibility is 212 * governed by the least accessible proxy interface. 213 * <p> 214 * Note that it is possible for arbitrary code to obtain access to a proxy class 215 * in an open package with {@link AccessibleObject#setAccessible setAccessible}, 216 * whereas a proxy class in a non-open package is never accessible to 217 * code outside the module of the proxy class. 218 * 219 * <p> 220 * Throughout this specification, a "non-exported package" refers to a package 221 * that is not exported to all modules, and a "non-open package" refers to 222 * a package that is not open to all modules. Specifically, these terms refer to 223 * a package that either is not exported/open by its containing module or is 224 * exported/open in a qualified fashion by its containing module. 225 * 226 * <h3><a id="dynamicmodule">Dynamic Modules</a></h3> 227 * <p> 228 * A dynamic module is a named module generated at runtime. A proxy class 229 * defined in a dynamic module is encapsulated and not accessible to any module. 230 * Calling {@link Constructor#newInstance(Object...)} on a proxy class in 231 * a dynamic module will throw {@code IllegalAccessException}; 232 * {@code Proxy.newProxyInstance} method should be used instead. 233 * 234 * <p> 235 * A dynamic module can read the modules of all of the superinterfaces of a proxy 236 * class and the modules of the classes and interfaces referenced by 237 * all public method signatures of a proxy class. If a superinterface or 238 * a referenced class or interface, say {@code T}, is in a non-exported package, 239 * the {@linkplain Module module} of {@code T} is updated to export the 240 * package of {@code T} to the dynamic module. 241 * 242 * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3> 243 * 244 * <p>When two or more proxy interfaces contain a method with 245 * the same name and parameter signature, the order of the proxy class's 246 * interfaces becomes significant. When such a <i>duplicate method</i> 247 * is invoked on a proxy instance, the {@code Method} object passed 248 * to the invocation handler will not necessarily be the one whose 249 * declaring class is assignable from the reference type of the interface 250 * that the proxy's method was invoked through. This limitation exists 251 * because the corresponding method implementation in the generated proxy 252 * class cannot determine which interface it was invoked through. 253 * Therefore, when a duplicate method is invoked on a proxy instance, 254 * the {@code Method} object for the method in the foremost interface 255 * that contains the method (either directly or inherited through a 256 * superinterface) in the proxy class's list of interfaces is passed to 257 * the invocation handler's {@code invoke} method, regardless of the 258 * reference type through which the method invocation occurred. 259 * 260 * <p>If a proxy interface contains a method with the same name and 261 * parameter signature as the {@code hashCode}, {@code equals}, 262 * or {@code toString} methods of {@code java.lang.Object}, 263 * when such a method is invoked on a proxy instance, the 264 * {@code Method} object passed to the invocation handler will have 265 * {@code java.lang.Object} as its declaring class. In other words, 266 * the public, non-final methods of {@code java.lang.Object} 267 * logically precede all of the proxy interfaces for the determination of 268 * which {@code Method} object to pass to the invocation handler. 269 * 270 * <p>Note also that when a duplicate method is dispatched to an 271 * invocation handler, the {@code invoke} method may only throw 272 * checked exception types that are assignable to one of the exception 273 * types in the {@code throws} clause of the method in <i>all</i> of 274 * the proxy interfaces that it can be invoked through. If the 275 * {@code invoke} method throws a checked exception that is not 276 * assignable to any of the exception types declared by the method in one 277 * of the proxy interfaces that it can be invoked through, then an 278 * unchecked {@code UndeclaredThrowableException} will be thrown by 279 * the invocation on the proxy instance. This restriction means that not 280 * all of the exception types returned by invoking 281 * {@code getExceptionTypes} on the {@code Method} object 282 * passed to the {@code invoke} method can necessarily be thrown 283 * successfully by the {@code invoke} method. 284 * 285 * @author Peter Jones 286 * @see InvocationHandler 287 * @since 1.3 288 */ 289 public class Proxy implements java.io.Serializable { 290 @java.io.Serial 291 private static final long serialVersionUID = -2222568056686623797L; 292 293 /** parameter types of a proxy class constructor */ 294 private static final Class<?>[] constructorParams = 295 { InvocationHandler.class }; 296 297 /** 298 * a cache of proxy constructors with 299 * {@link Constructor#setAccessible(boolean) accessible} flag already set 300 */ 301 private static final ClassLoaderValue<Constructor<?>> proxyCache = 302 new ClassLoaderValue<>(); 303 304 /** 305 * the invocation handler for this proxy instance. 306 * @serial 307 */ 308 @SuppressWarnings("serial") // Not statically typed as Serializable 309 protected InvocationHandler h; 310 311 /** 312 * Prohibits instantiation. 313 */ 314 private Proxy() { 315 } 316 317 /** 318 * Constructs a new {@code Proxy} instance from a subclass 319 * (typically, a dynamic proxy class) with the specified value 320 * for its invocation handler. 321 * 322 * @param h the invocation handler for this proxy instance 323 * 324 * @throws NullPointerException if the given invocation handler, {@code h}, 325 * is {@code null}. 326 */ 327 protected Proxy(InvocationHandler h) { 328 Objects.requireNonNull(h); 329 this.h = h; 330 } 331 332 /** 333 * Returns the {@code java.lang.Class} object for a proxy class 334 * given a class loader and an array of interfaces. The proxy class 335 * will be defined by the specified class loader and will implement 336 * all of the supplied interfaces. If any of the given interfaces 337 * is non-public, the proxy class will be non-public. If a proxy class 338 * for the same permutation of interfaces has already been defined by the 339 * class loader, then the existing proxy class will be returned; otherwise, 340 * a proxy class for those interfaces will be generated dynamically 341 * and defined by the class loader. 342 * 343 * @param loader the class loader to define the proxy class 344 * @param interfaces the list of interfaces for the proxy class 345 * to implement 346 * @return a proxy class that is defined in the specified class loader 347 * and that implements the specified interfaces 348 * @throws IllegalArgumentException if any of the <a href="#restrictions"> 349 * restrictions</a> on the parameters are violated 350 * @throws NullPointerException if the {@code interfaces} array 351 * argument or any of its elements are {@code null} 352 * 353 * @deprecated Proxy classes generated in a named module are encapsulated 354 * and not accessible to code outside its module. 355 * {@link Constructor#newInstance(Object...) Constructor.newInstance} 356 * will throw {@code IllegalAccessException} when it is called on 357 * an inaccessible proxy class. 358 * Use {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)} 359 * to create a proxy instance instead. 360 * 361 * @see <a href="#membership">Package and Module Membership of Proxy Class</a> 362 */ 363 @Deprecated 364 public static Class<?> getProxyClass(ClassLoader loader, 365 Class<?>... interfaces) 366 throws IllegalArgumentException 367 { 368 return getProxyConstructor(loader, interfaces) 369 .getDeclaringClass(); 370 } 371 372 /** 373 * Returns the {@code Constructor} object of a proxy class that takes a 374 * single argument of type {@link InvocationHandler}, given a class loader 375 * and an array of interfaces. The returned constructor will have the 376 * {@link Constructor#setAccessible(boolean) accessible} flag already set. 377 * 378 * @param loader the class loader to define the proxy class 379 * @param interfaces the list of interfaces for the proxy class 380 * to implement 381 * @return a Constructor of the proxy class taking single 382 * {@code InvocationHandler} parameter 383 */ 384 private static Constructor<?> getProxyConstructor(ClassLoader loader, 385 Class<?>... interfaces) 386 { 387 // optimization for single interface 388 if (interfaces.length == 1) { 389 Class<?> intf = interfaces[0]; 390 return proxyCache.sub(intf).computeIfAbsent( 391 loader, 392 (ld, clv) -> new ProxyBuilder(ld, clv.key()).build() 393 ); 394 } else { 395 // interfaces cloned 396 final Class<?>[] intfsArray = interfaces.clone(); 397 final List<Class<?>> intfs = Arrays.asList(intfsArray); 398 return proxyCache.sub(intfs).computeIfAbsent( 399 loader, 400 (ld, clv) -> new ProxyBuilder(ld, clv.key()).build() 401 ); 402 } 403 } 404 405 /** 406 * Called from VM native code during dump time. 407 */ 408 private static void initCacheForCDS(ClassLoader platformLoader, ClassLoader appLoader) { 409 ProxyBuilder.initCacheForCDS(platformLoader, appLoader); 410 } 411 412 /** 413 * Builder for a proxy class. 414 * 415 * If the module is not specified in this ProxyBuilder constructor, 416 * it will map from the given loader and interfaces to the module 417 * in which the proxy class will be defined. 418 */ 419 private static final class ProxyBuilder { 420 private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); 421 422 private static String makeProxyClassNamePrefix() { 423 // Allow unique proxy names to be used across CDS dump time and app run time. 424 if (CDS.isDumpingArchive()) { 425 if (CDS.isUsingArchive()) { 426 return "$Proxy0100"; // CDS dynamic dump 427 } else { 428 return "$Proxy0010"; // CDS static dump 429 } 430 } else { 431 return "$Proxy"; 432 } 433 } 434 435 // prefix for all proxy class names 436 private static final String proxyClassNamePrefix = makeProxyClassNamePrefix(); 437 438 // next number to use for generation of unique proxy class names 439 private static final AtomicLong nextUniqueNumber = new AtomicLong(); 440 441 // a reverse cache of defined proxy classes 442 private static final ClassLoaderValue<Boolean> reverseProxyCache = 443 new ClassLoaderValue<>(); 444 445 private record ProxyClassContext(Module module, String packageName, int accessFlags, boolean isDynamicModule) { 446 private ProxyClassContext { 447 if (module.isNamed()) { 448 if (packageName.isEmpty()) { 449 // Per JLS 7.4.2, unnamed package can only exist in unnamed modules. 450 // This means a package-private superinterface exist in the unnamed 451 // package of a named module. 452 throw new InternalError("Unnamed package cannot be added to " + module); 453 } 454 455 if (!module.getDescriptor().packages().contains(packageName)) { 456 throw new InternalError(packageName + " not exist in " + module.getName()); 457 } 458 459 if (!module.isOpen(packageName, Proxy.class.getModule())) { 460 // Required for default method invocation 461 throw new InternalError(packageName + " not open to " + Proxy.class.getModule()); 462 } 463 } else { 464 if (Modifier.isPublic(accessFlags)) { 465 // All proxy superinterfaces are public, must be in named dynamic module 466 throw new InternalError("public proxy in unnamed module: " + module); 467 } 468 } 469 470 if ((accessFlags & ~Modifier.PUBLIC) != 0) { 471 throw new InternalError("proxy access flags must be Modifier.PUBLIC or 0"); 472 } 473 } 474 } 475 476 private static Class<?> defineProxyClass(ProxyClassContext context, List<Class<?>> interfaces) { 477 /* 478 * Choose a name for the proxy class to generate. 479 */ 480 String packagePrefix = context.packageName().isEmpty() 481 ? proxyClassNamePrefix 482 : context.packageName() + "." + proxyClassNamePrefix; 483 ClassLoader loader = context.module().getClassLoader(); 484 int accessFlags = context.accessFlags() | Modifier.FINAL; 485 486 if (archivedData != null) { 487 Class<?> pc = archivedData.getArchivedProxyClass(loader, packagePrefix, interfaces); 488 if (pc != null) { 489 reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE); 490 return pc; 491 } 492 } 493 494 long num = nextUniqueNumber.getAndIncrement(); 495 String proxyName = packagePrefix + num; 496 497 trace(proxyName, context.module(), loader, interfaces); 498 499 if (CDS.isLoggingDynamicProxies() && context.isDynamicModule()) { 500 CDS.logDynamicProxy(loader, proxyName, interfaces.toArray(new Class<?>[0]), accessFlags); 501 } 502 503 /* 504 * Generate the specified proxy class. 505 */ 506 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags); 507 try { 508 Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile, 509 null, "__dynamic_proxy__"); 510 reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE); 511 return pc; 512 } catch (ClassFormatError e) { 513 /* 514 * A ClassFormatError here means that (barring bugs in the 515 * proxy class generation code) there was some other 516 * invalid aspect of the arguments supplied to the proxy 517 * class creation (such as virtual machine limitations 518 * exceeded). 519 */ 520 throw new IllegalArgumentException(e.toString()); 521 } 522 } 523 524 /** 525 * Called from VM native code to define a proxy class to be stored in archivedData. 526 */ 527 private static Class<?> defineProxyClassForCDS(ClassLoader loader, String proxyName, Class<?>[] interfaces, 528 int accessFlags) { 529 ArrayList<Class<?>> list = new ArrayList<>(); 530 for (Object o : interfaces) { 531 list.add((Class<?>)o); 532 } 533 534 ProxyBuilder builder = new ProxyBuilder(loader, list); 535 Constructor<?> cons = builder.build(); 536 Class<?> proxyClass = cons.getDeclaringClass(); 537 archivedData.putArchivedProxyClass(loader, proxyName, list, proxyClass); 538 return proxyClass; 539 } 540 541 /** 542 * Test if given class is a class defined by 543 * {@link #defineProxyClass(ProxyClassContext, List)} 544 */ 545 static boolean isProxyClass(Class<?> c) { 546 return Objects.equals(reverseProxyCache.sub(c).get(c.getClassLoader()), 547 Boolean.TRUE); 548 } 549 550 private static boolean isExportedType(Class<?> c) { 551 String pn = c.getPackageName(); 552 return Modifier.isPublic(c.getModifiers()) && c.getModule().isExported(pn); 553 } 554 555 private static boolean isPackagePrivateType(Class<?> c) { 556 return !Modifier.isPublic(c.getModifiers()); 557 } 558 559 private static String toDetails(Class<?> c) { 560 String access = "unknown"; 561 if (isExportedType(c)) { 562 access = "exported"; 563 } else if (isPackagePrivateType(c)) { 564 access = "package-private"; 565 } else { 566 access = "module-private"; 567 } 568 ClassLoader ld = c.getClassLoader(); 569 return String.format(" %s/%s %s loader %s", 570 c.getModule().getName(), c.getName(), access, ld); 571 } 572 573 static void trace(String cn, 574 Module module, 575 ClassLoader loader, 576 List<Class<?>> interfaces) { 577 if (isDebug()) { 578 System.err.format("PROXY: %s/%s defined by %s%n", 579 module.getName(), cn, loader); 580 } 581 if (isDebug("debug")) { 582 interfaces.forEach(c -> System.out.println(toDetails(c))); 583 } 584 } 585 586 private static final String DEBUG = System.getProperty("jdk.proxy.debug", ""); 587 588 private static boolean isDebug() { 589 return !DEBUG.isEmpty(); 590 } 591 private static boolean isDebug(String flag) { 592 return DEBUG.equals(flag); 593 } 594 595 // ProxyBuilder instance members start here.... 596 597 private final List<Class<?>> interfaces; 598 private final ProxyClassContext context; 599 ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) { 600 Objects.requireNonNull(interfaces); 601 if (!VM.isModuleSystemInited()) { 602 throw new InternalError("Proxy is not supported until " 603 + "module system is fully initialized"); 604 } 605 if (interfaces.size() > 65535) { 606 throw new IllegalArgumentException("interface limit exceeded: " 607 + interfaces.size()); 608 } 609 610 Set<Class<?>> refTypes = referencedTypes(loader, interfaces); 611 612 // IAE if violates any restrictions specified in newProxyInstance 613 validateProxyInterfaces(loader, interfaces, refTypes); 614 615 this.interfaces = interfaces; 616 this.context = proxyClassContext(loader, interfaces, refTypes); 617 assert context.module().getClassLoader() == loader; 618 } 619 620 ProxyBuilder(ClassLoader loader, Class<?> intf) { 621 this(loader, Collections.singletonList(intf)); 622 } 623 624 /** 625 * Generate a proxy class and return its proxy Constructor with 626 * accessible flag already set. If the target module does not have access 627 * to any interface types, IllegalAccessError will be thrown by the VM 628 * at defineClass time. 629 */ 630 Constructor<?> build() { 631 Class<?> proxyClass = defineProxyClass(context, interfaces); 632 633 final Constructor<?> cons; 634 try { 635 cons = proxyClass.getConstructor(constructorParams); 636 } catch (NoSuchMethodException e) { 637 throw new InternalError(e.toString(), e); 638 } 639 cons.setAccessible(true); 640 return cons; 641 } 642 643 /** 644 * Validate the given proxy interfaces and the given referenced types 645 * are visible to the defining loader. 646 * 647 * @throws IllegalArgumentException if it violates the restrictions 648 * specified in {@link Proxy#newProxyInstance} 649 */ 650 private static void validateProxyInterfaces(ClassLoader loader, 651 List<Class<?>> interfaces, 652 Set<Class<?>> refTypes) 653 { 654 Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.size()); 655 for (Class<?> intf : interfaces) { 656 /* 657 * Verify that the Class object actually represents an 658 * interface. 659 */ 660 if (!intf.isInterface()) { 661 throw new IllegalArgumentException(intf.getName() + " is not an interface"); 662 } 663 664 if (intf.isHidden()) { 665 throw new IllegalArgumentException(intf.getName() + " is a hidden interface"); 666 } 667 668 if (intf.isSealed()) { 669 throw new IllegalArgumentException(intf.getName() + " is a sealed interface"); 670 } 671 672 /* 673 * Verify that the class loader resolves the name of this 674 * interface to the same Class object. 675 */ 676 ensureVisible(loader, intf); 677 678 /* 679 * Verify that this interface is not a duplicate. 680 */ 681 if (interfaceSet.put(intf, Boolean.TRUE) != null) { 682 throw new IllegalArgumentException("repeated interface: " + intf.getName()); 683 } 684 } 685 686 for (Class<?> type : refTypes) { 687 ensureVisible(loader, type); 688 } 689 } 690 691 /* 692 * Returns all types referenced by all public non-static method signatures of 693 * the proxy interfaces 694 */ 695 private static Set<Class<?>> referencedTypes(ClassLoader loader, 696 List<Class<?>> interfaces) { 697 var types = new HashSet<Class<?>>(); 698 for (var intf : interfaces) { 699 for (Method m : intf.getMethods()) { 700 if (!Modifier.isStatic(m.getModifiers())) { 701 addElementType(types, m.getReturnType()); 702 addElementTypes(types, m.getSharedParameterTypes()); 703 addElementTypes(types, m.getSharedExceptionTypes()); 704 } 705 } 706 } 707 return types; 708 } 709 710 private static void addElementTypes(HashSet<Class<?>> types, 711 Class<?> ... classes) { 712 for (var cls : classes) { 713 addElementType(types, cls); 714 } 715 } 716 717 private static void addElementType(HashSet<Class<?>> types, 718 Class<?> cls) { 719 var type = getElementType(cls); 720 if (!type.isPrimitive()) { 721 types.add(type); 722 } 723 } 724 725 /** 726 * Returns the context for the generated proxy class, including the 727 * module and the package it belongs to and whether it is package-private. 728 * 729 * If any of proxy interface is package-private, then the proxy class 730 * is in the same package and module as the package-private interface. 731 * 732 * If all proxy interfaces are public and in exported packages, 733 * then the proxy class is in a dynamic module in an unconditionally 734 * exported package. 735 * 736 * If all proxy interfaces are public and at least one in a non-exported 737 * package, then the proxy class is in a dynamic module in a 738 * non-exported package. 739 * 740 * The package of proxy class is open to java.base for deep reflective access. 741 * 742 * Reads edge and qualified exports are added for dynamic module to access. 743 */ 744 private static ProxyClassContext proxyClassContext(ClassLoader loader, 745 List<Class<?>> interfaces, 746 Set<Class<?>> refTypes) { 747 Map<Class<?>, Module> packagePrivateTypes = new HashMap<>(); 748 boolean nonExported = false; 749 750 for (Class<?> intf : interfaces) { 751 Module m = intf.getModule(); 752 if (!Modifier.isPublic(intf.getModifiers())) { 753 packagePrivateTypes.put(intf, m); 754 } else { 755 if (!intf.getModule().isExported(intf.getPackageName())) { 756 // module-private types 757 nonExported = true; 758 } 759 } 760 } 761 762 if (packagePrivateTypes.size() > 0) { 763 // all package-private types must be in the same runtime package 764 // i.e. same package name and same module (named or unnamed) 765 // 766 // Configuration will fail if M1 and in M2 defined by the same loader 767 // and both have the same package p (so no need to check class loader) 768 Module targetModule = null; 769 String targetPackageName = null; 770 for (Map.Entry<Class<?>, Module> e : packagePrivateTypes.entrySet()) { 771 Class<?> intf = e.getKey(); 772 Module m = e.getValue(); 773 if ((targetModule != null && targetModule != m) || 774 (targetPackageName != null && targetPackageName != intf.getPackageName())) { 775 throw new IllegalArgumentException( 776 "cannot have non-public interfaces in different packages"); 777 } 778 if (m.getClassLoader() != loader) { 779 // the specified loader is not the same class loader 780 // of the non-public interface 781 throw new IllegalArgumentException( 782 "non-public interface is not defined by the given loader"); 783 } 784 785 targetModule = m; 786 targetPackageName = e.getKey().getPackageName(); 787 } 788 789 // validate if the target module can access all other interfaces 790 for (Class<?> intf : interfaces) { 791 Module m = intf.getModule(); 792 if (m == targetModule) continue; 793 794 if (!targetModule.canRead(m) || !m.isExported(intf.getPackageName(), targetModule)) { 795 throw new IllegalArgumentException(targetModule + " can't access " + intf.getName()); 796 } 797 } 798 799 // opens the package of the non-public proxy class for java.base to access 800 if (targetModule.isNamed()) { 801 Modules.addOpens(targetModule, targetPackageName, Proxy.class.getModule()); 802 } 803 // return the module of the package-private interface 804 return new ProxyClassContext(targetModule, targetPackageName, 0, false); 805 } 806 807 // All proxy interfaces are public. So maps to a dynamic proxy module 808 // and add reads edge and qualified exports, if necessary 809 Module targetModule = getDynamicModule(loader); 810 811 // set up proxy class access to proxy interfaces and types 812 // referenced in the method signature 813 Set<Class<?>> types = new HashSet<>(interfaces); 814 types.addAll(refTypes); 815 for (Class<?> c : types) { 816 ensureAccess(targetModule, c); 817 } 818 819 var pkgName = nonExported ? PROXY_PACKAGE_PREFIX + '.' + targetModule.getName() 820 : targetModule.getName(); 821 return new ProxyClassContext(targetModule, pkgName, Modifier.PUBLIC, true); 822 } 823 824 /* 825 * Ensure the given module can access the given class. 826 */ 827 private static void ensureAccess(Module target, Class<?> c) { 828 Module m = c.getModule(); 829 if (target == m) return; 830 831 // add read edge and qualified export for the target module to access 832 if (!target.canRead(m)) { 833 Modules.addReads(target, m); 834 } 835 String pn = c.getPackageName(); 836 if (!m.isExported(pn, target)) { 837 Modules.addExports(m, pn, target); 838 } 839 } 840 841 /* 842 * Ensure the given class is visible to the class loader. 843 */ 844 private static void ensureVisible(ClassLoader ld, Class<?> c) { 845 Class<?> type = null; 846 try { 847 type = Class.forName(c.getName(), false, ld); 848 } catch (ClassNotFoundException e) { 849 } 850 if (type != c) { 851 throw new IllegalArgumentException(c.getName() + 852 " referenced from a method is not visible from class loader: " + JLA.getLoaderNameID(ld)); 853 } 854 } 855 856 private static Class<?> getElementType(Class<?> type) { 857 Class<?> e = type; 858 while (e.isArray()) { 859 e = e.getComponentType(); 860 } 861 return e; 862 } 863 864 private static final ClassLoaderValue<Module> dynProxyModules = 865 new ClassLoaderValue<>(); 866 private static final AtomicInteger counter = new AtomicInteger(); 867 868 /* 869 * Define a dynamic module with a package named $MODULE which 870 * is unconditionally exported and another package named 871 * com.sun.proxy.$MODULE which is encapsulated. 872 * 873 * Each class loader will have one dynamic module. 874 */ 875 private static Module getDynamicModule(ClassLoader loader) { 876 return dynProxyModules.computeIfAbsent(loader, (ld, clv) -> { 877 // create a dynamic module and setup module access 878 int num = counter.incrementAndGet(); 879 String mn = "jdk.proxy" + num; 880 String pn = PROXY_PACKAGE_PREFIX + "." + mn; 881 ModuleDescriptor descriptor = 882 ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC)) 883 .packages(Set.of(pn, mn)) 884 .exports(mn) 885 .build(); 886 Module m = Modules.defineModule(ld, descriptor, null); 887 openDynamicModule(m); 888 889 if (CDS.isDumpingHeap() && archivedData != null) { 890 archivedData.recordModule(loader, m, num); 891 } 892 return m; 893 }); 894 } 895 896 private static void openDynamicModule(Module m) { 897 String mn = m.getName(); 898 String pn = PROXY_PACKAGE_PREFIX + "." + mn; 899 Modules.addReads(m, Proxy.class.getModule()); 900 Modules.addExports(m, mn); 901 // java.base to create proxy instance and access its Lookup instance 902 Modules.addOpens(m, pn, Proxy.class.getModule()); 903 Modules.addOpens(m, mn, Proxy.class.getModule()); 904 } 905 906 static class ArchivedData { 907 static class InterfacesKey { 908 Class<?>[] intfsArray; 909 InterfacesKey(List<Class<?>> intfs) { 910 intfsArray = new Class<?>[intfs.size()]; 911 for (int i = 0; i < intfs.size(); i++) { 912 intfsArray[i] = intfs.get(i); 913 } 914 } 915 @Override 916 public int hashCode() { 917 return Arrays.hashCode(intfsArray); 918 } 919 @Override 920 public boolean equals(Object other) { 921 if (other instanceof InterfacesKey) { 922 InterfacesKey o = (InterfacesKey)other; 923 int len = intfsArray.length; 924 if (len != o.intfsArray.length) { 925 return false; 926 } 927 Class<?>[] oa = o.intfsArray; 928 for (int i = 0; i < len; i++) { 929 if (intfsArray[i] != oa[i]) { 930 return false; 931 } 932 } 933 return true; 934 } else { 935 return false; 936 } 937 } 938 } 939 940 ClassLoader platformLoader; 941 ClassLoader appLoader; 942 HashMap<InterfacesKey,Class<?>> bootCache = new HashMap<>(); 943 HashMap<InterfacesKey,Class<?>> platformCache = new HashMap<>(); 944 HashMap<InterfacesKey,Class<?>> appCache = new HashMap<>(); 945 946 Module bootModule; 947 Module platformModule; 948 Module appModule; 949 int maxNum; 950 951 ArchivedData(ClassLoader plat, ClassLoader app) { 952 platformLoader = plat; 953 appLoader = app; 954 } 955 956 HashMap<InterfacesKey,Class<?>> cacheForLoader(ClassLoader loader) { 957 if (loader == null) { 958 return bootCache; 959 } else if (loader == platformLoader) { 960 return platformCache; 961 } else if (loader == appLoader) { 962 return appCache; 963 } else { 964 return null; 965 } 966 } 967 968 void recordModule(ClassLoader loader, Module m, int num) { 969 if (loader == null) { 970 bootModule = m; 971 } else if (loader == platformLoader) { 972 platformModule = m; 973 } else if (loader == appLoader) { 974 appModule = m; 975 } else { 976 throw new UnsupportedOperationException("Class loader " + loader + " is not supported"); 977 } 978 if (maxNum < num) { 979 maxNum = num; 980 } 981 } 982 983 void restore() { 984 // The info for addReads/addExports/addOpens are maintained solely inside the VM. 985 // CDS currently doesn't properly archive such info for the dynamically generated modules, 986 // so we have to recreate them at runtime. 987 // 988 // TODO -- consider improving CDS to archive the above info, so we can avoid calling openDynamicModule() 989 if (bootModule != null) { 990 Module last = dynProxyModules.putIfAbsent(null, bootModule); 991 assert last == null; 992 openDynamicModule(bootModule); 993 } 994 if (platformModule != null) { 995 Module last = dynProxyModules.putIfAbsent(platformLoader, platformModule); 996 assert last == null; 997 openDynamicModule(platformModule); 998 } 999 if (appModule != null) { 1000 Module last = dynProxyModules.putIfAbsent(appLoader, appModule); 1001 assert last == null; 1002 openDynamicModule(appModule); 1003 } 1004 1005 while (maxNum > counter.get()) { 1006 counter.incrementAndGet(); 1007 } 1008 } 1009 1010 1011 Class<?> getArchivedProxyClass(ClassLoader loader, String proxyPrefix, List<Class<?>> interfaces) { 1012 HashMap<InterfacesKey,Class<?>> cache = cacheForLoader(loader); 1013 if (cache != null && cache.size() > 0) { 1014 InterfacesKey key = new InterfacesKey(interfaces); 1015 return cache.get(key); 1016 } else { 1017 return null; 1018 } 1019 } 1020 1021 void putArchivedProxyClass(ClassLoader loader, String proxyName, List<Class<?>> interfaces, Class<?> cls) { 1022 HashMap<InterfacesKey,Class<?>> cache = cacheForLoader(loader); 1023 if (cache != null) { 1024 InterfacesKey key = new InterfacesKey(interfaces); 1025 cache.put(key, cls); 1026 } 1027 } 1028 } 1029 1030 static ArchivedData archivedData; 1031 1032 static { 1033 CDS.initializeFromArchive(ProxyBuilder.class); 1034 if (archivedData != null) { 1035 archivedData.restore(); 1036 } 1037 } 1038 1039 private static void initCacheForCDS(ClassLoader platformLoader, ClassLoader appLoader) { 1040 archivedData = new ArchivedData(platformLoader, appLoader); 1041 } 1042 } 1043 1044 /** 1045 * Returns a proxy instance for the specified interfaces 1046 * that dispatches method invocations to the specified invocation 1047 * handler. 1048 * <p> 1049 * <a id="restrictions">{@code IllegalArgumentException} will be thrown 1050 * if any of the following restrictions is violated:</a> 1051 * <ul> 1052 * <li>All of {@code Class} objects in the given {@code interfaces} array 1053 * must represent {@linkplain Class#isHidden() non-hidden} and 1054 * {@linkplain Class#isSealed() non-sealed} interfaces, 1055 * not classes or primitive types. 1056 * 1057 * <li>No two elements in the {@code interfaces} array may 1058 * refer to identical {@code Class} objects. 1059 * 1060 * <li>All of the interface types must be visible by name through the 1061 * specified class loader. In other words, for class loader 1062 * {@code cl} and every interface {@code i}, the following 1063 * expression must be true:<p> 1064 * {@code Class.forName(i.getName(), false, cl) == i} 1065 * 1066 * <li>All of the types referenced by all 1067 * public method signatures of the specified interfaces 1068 * and those inherited by their superinterfaces 1069 * must be visible by name through the specified class loader. 1070 * 1071 * <li>All non-public interfaces must be in the same package 1072 * and module, defined by the specified class loader and 1073 * the module of the non-public interfaces can access all of 1074 * the interface types; otherwise, it would not be possible for 1075 * the proxy class to implement all of the interfaces, 1076 * regardless of what package it is defined in. 1077 * 1078 * <li>For any set of member methods of the specified interfaces 1079 * that have the same signature: 1080 * <ul> 1081 * <li>If the return type of any of the methods is a primitive 1082 * type or void, then all of the methods must have that same 1083 * return type. 1084 * <li>Otherwise, one of the methods must have a return type that 1085 * is assignable to all of the return types of the rest of the 1086 * methods. 1087 * </ul> 1088 * 1089 * <li>The resulting proxy class must not exceed any limits imposed 1090 * on classes by the virtual machine. For example, the VM may limit 1091 * the number of interfaces that a class may implement to 65535; in 1092 * that case, the size of the {@code interfaces} array must not 1093 * exceed 65535. 1094 * </ul> 1095 * 1096 * <p>Note that the order of the specified proxy interfaces is 1097 * significant: two requests for a proxy class with the same combination 1098 * of interfaces but in a different order will result in two distinct 1099 * proxy classes. 1100 * 1101 * @param loader the class loader to define the proxy class 1102 * @param interfaces the list of interfaces for the proxy class 1103 * to implement 1104 * @param h the invocation handler to dispatch method invocations to 1105 * @return a proxy instance with the specified invocation handler of a 1106 * proxy class that is defined by the specified class loader 1107 * and that implements the specified interfaces 1108 * @throws IllegalArgumentException if any of the <a href="#restrictions"> 1109 * restrictions</a> on the parameters are violated 1110 * @throws NullPointerException if the {@code interfaces} array 1111 * argument or any of its elements are {@code null}, or 1112 * if the invocation handler, {@code h}, is 1113 * {@code null} 1114 * 1115 * @see <a href="#membership">Package and Module Membership of Proxy Class</a> 1116 */ 1117 public static Object newProxyInstance(ClassLoader loader, 1118 Class<?>[] interfaces, 1119 InvocationHandler h) { 1120 Objects.requireNonNull(h); 1121 1122 /* 1123 * Look up or generate the designated proxy class and its constructor. 1124 */ 1125 Constructor<?> cons = getProxyConstructor(loader, interfaces); 1126 1127 return newProxyInstance(cons, h); 1128 } 1129 1130 private static Object newProxyInstance(Constructor<?> cons, InvocationHandler h) { 1131 /* 1132 * Invoke its constructor with the designated invocation handler. 1133 */ 1134 try { 1135 return cons.newInstance(new Object[]{h}); 1136 } catch (IllegalAccessException | InstantiationException e) { 1137 throw new InternalError(e.toString(), e); 1138 } catch (InvocationTargetException e) { 1139 Throwable t = e.getCause(); 1140 if (t instanceof RuntimeException re) { 1141 throw re; 1142 } else { 1143 throw new InternalError(t.toString(), t); 1144 } 1145 } 1146 } 1147 1148 /** 1149 * Returns true if the given class is a proxy class. 1150 * 1151 * @implNote The reliability of this method is important for the ability 1152 * to use it to make security decisions, so its implementation should 1153 * not just test if the class in question extends {@code Proxy}. 1154 * 1155 * @param cl the class to test 1156 * @return {@code true} if the class is a proxy class and 1157 * {@code false} otherwise 1158 * @throws NullPointerException if {@code cl} is {@code null} 1159 */ 1160 public static boolean isProxyClass(Class<?> cl) { 1161 return Proxy.class.isAssignableFrom(cl) && ProxyBuilder.isProxyClass(cl); 1162 } 1163 1164 /** 1165 * Returns the invocation handler for the specified proxy instance. 1166 * 1167 * @param proxy the proxy instance to return the invocation handler for 1168 * @return the invocation handler for the proxy instance 1169 * @throws IllegalArgumentException if the argument is not a 1170 * proxy instance 1171 */ 1172 public static InvocationHandler getInvocationHandler(Object proxy) 1173 throws IllegalArgumentException 1174 { 1175 /* 1176 * Verify that the object is actually a proxy instance. 1177 */ 1178 if (!isProxyClass(proxy.getClass())) { 1179 throw new IllegalArgumentException("not a proxy instance"); 1180 } 1181 1182 final Proxy p = (Proxy) proxy; 1183 final InvocationHandler ih = p.h; 1184 return ih; 1185 } 1186 1187 private static final String PROXY_PACKAGE_PREFIX = "com.sun.proxy"; 1188 1189 /** 1190 * A cache of Method -> MethodHandle for default methods. 1191 */ 1192 private static final ClassValue<ConcurrentHashMap<Method, MethodHandle>> 1193 DEFAULT_METHODS_MAP = new ClassValue<>() { 1194 @Override 1195 protected ConcurrentHashMap<Method, MethodHandle> computeValue(Class<?> type) { 1196 return new ConcurrentHashMap<>(4); 1197 } 1198 }; 1199 1200 private static ConcurrentHashMap<Method, MethodHandle> defaultMethodMap(Class<?> proxyClass) { 1201 assert isProxyClass(proxyClass); 1202 return DEFAULT_METHODS_MAP.get(proxyClass); 1203 } 1204 1205 static final Object[] EMPTY_ARGS = new Object[0]; 1206 1207 static MethodHandle defaultMethodHandle(Class<? extends Proxy> proxyClass, Method method) { 1208 // lookup the cached method handle 1209 ConcurrentHashMap<Method, MethodHandle> methods = defaultMethodMap(proxyClass); 1210 MethodHandle superMH = methods.get(method); 1211 if (superMH == null) { 1212 MethodType type = methodType(method.getReturnType(), method.getParameterTypes()); 1213 MethodHandles.Lookup lookup = MethodHandles.lookup(); 1214 Class<?> proxyInterface = findProxyInterfaceOrElseThrow(proxyClass, method); 1215 MethodHandle dmh; 1216 try { 1217 dmh = proxyClassLookup(lookup, proxyClass) 1218 .findSpecial(proxyInterface, method.getName(), type, proxyClass) 1219 .withVarargs(false); 1220 } catch (IllegalAccessException | NoSuchMethodException e) { 1221 // should not reach here 1222 throw new InternalError(e); 1223 } 1224 // this check can be turned into assertion as it is guaranteed to succeed by the virtue of 1225 // looking up a default (instance) method declared or inherited by proxyInterface 1226 // while proxyClass implements (is a subtype of) proxyInterface ... 1227 assert ((BooleanSupplier) () -> { 1228 try { 1229 // make sure that the method type matches 1230 dmh.asType(type.insertParameterTypes(0, proxyClass)); 1231 return true; 1232 } catch (WrongMethodTypeException e) { 1233 return false; 1234 } 1235 }).getAsBoolean() : "Wrong method type"; 1236 // change return type to Object 1237 MethodHandle mh = dmh.asType(dmh.type().changeReturnType(Object.class)); 1238 // wrap any exception thrown with InvocationTargetException 1239 mh = MethodHandles.catchException(mh, Throwable.class, InvocationException.wrapMH()); 1240 // spread array of arguments among parameters (skipping 1st parameter - target) 1241 mh = mh.asSpreader(1, Object[].class, type.parameterCount()); 1242 // change target type to Object 1243 mh = mh.asType(MethodType.methodType(Object.class, Object.class, Object[].class)); 1244 1245 // push MH into cache 1246 MethodHandle cached = methods.putIfAbsent(method, mh); 1247 if (cached != null) { 1248 superMH = cached; 1249 } else { 1250 superMH = mh; 1251 } 1252 } 1253 return superMH; 1254 } 1255 1256 /** 1257 * Finds the first proxy interface that declares the given method 1258 * directly or indirectly. 1259 * 1260 * @throws IllegalArgumentException if not found 1261 */ 1262 private static Class<?> findProxyInterfaceOrElseThrow(Class<?> proxyClass, Method method) { 1263 Class<?> declaringClass = method.getDeclaringClass(); 1264 if (!declaringClass.isInterface()) { 1265 throw new IllegalArgumentException("\"" + method + 1266 "\" is not a method declared in the proxy class"); 1267 } 1268 1269 List<Class<?>> proxyInterfaces = Arrays.asList(proxyClass.getInterfaces()); 1270 // the method's declaring class is a proxy interface 1271 if (proxyInterfaces.contains(declaringClass)) 1272 return declaringClass; 1273 1274 // find the first proxy interface that inherits the default method 1275 // i.e. the declaring class of the default method is a superinterface 1276 // of the proxy interface 1277 Deque<Class<?>> deque = new ArrayDeque<>(); 1278 Set<Class<?>> visited = new HashSet<>(); 1279 boolean indirectMethodRef = false; 1280 for (Class<?> proxyIntf : proxyInterfaces) { 1281 assert proxyIntf != declaringClass; 1282 visited.add(proxyIntf); 1283 deque.add(proxyIntf); 1284 1285 // for each proxy interface, traverse its subinterfaces with 1286 // breadth-first search to find a subinterface declaring the 1287 // default method 1288 Class<?> c; 1289 while ((c = deque.poll()) != null) { 1290 if (c == declaringClass) { 1291 try { 1292 // check if this method is the resolved method if referenced from 1293 // this proxy interface (i.e. this method is not implemented 1294 // by any other superinterface) 1295 Method m = proxyIntf.getMethod(method.getName(), method.getSharedParameterTypes()); 1296 if (m.getDeclaringClass() == declaringClass) { 1297 return proxyIntf; 1298 } 1299 indirectMethodRef = true; 1300 } catch (NoSuchMethodException e) {} 1301 1302 // skip traversing its superinterfaces 1303 // another proxy interface may extend it and so 1304 // the method's declaring class is left unvisited. 1305 continue; 1306 } 1307 // visit all superinterfaces of one proxy interface to find if 1308 // this proxy interface inherits the method directly or indirectly 1309 visited.add(c); 1310 for (Class<?> superIntf : c.getInterfaces()) { 1311 if (!visited.contains(superIntf) && !deque.contains(superIntf)) { 1312 if (superIntf == declaringClass) { 1313 // fast-path as the matching subinterface is found 1314 deque.addFirst(superIntf); 1315 } else { 1316 deque.add(superIntf); 1317 } 1318 } 1319 } 1320 } 1321 } 1322 1323 throw new IllegalArgumentException("\"" + method + (indirectMethodRef 1324 ? "\" is overridden directly or indirectly by the proxy interfaces" 1325 : "\" is not a method declared in the proxy class")); 1326 } 1327 1328 /** 1329 * This method invokes the proxy's proxyClassLookup method to get a 1330 * Lookup on the proxy class. 1331 * 1332 * @return a lookup for proxy class of this proxy instance 1333 */ 1334 private static MethodHandles.Lookup proxyClassLookup(MethodHandles.Lookup caller, Class<?> proxyClass) { 1335 try { 1336 Method m = proxyClass.getDeclaredMethod("proxyClassLookup", MethodHandles.Lookup.class); 1337 m.setAccessible(true); 1338 return (MethodHandles.Lookup) m.invoke(null, caller); 1339 } catch (ReflectiveOperationException e) { 1340 throw new InternalError(e); 1341 } 1342 } 1343 1344 /* 1345 * Invoke the default method of the given proxy with an explicit caller class. 1346 * 1347 * @throws IllegalAccessException if the proxy interface is inaccessible to the caller 1348 * if caller is non-null 1349 */ 1350 static Object invokeDefault(Object proxy, Method method, Object[] args, Class<?> caller) 1351 throws Throwable { 1352 // verify that the object is actually a proxy instance 1353 if (!Proxy.isProxyClass(proxy.getClass())) { 1354 throw new IllegalArgumentException("'proxy' is not a proxy instance"); 1355 } 1356 if (!method.isDefault()) { 1357 throw new IllegalArgumentException("\"" + method + "\" is not a default method"); 1358 } 1359 @SuppressWarnings("unchecked") 1360 Class<? extends Proxy> proxyClass = (Class<? extends Proxy>)proxy.getClass(); 1361 1362 // skip access check if caller is null 1363 if (caller != null) { 1364 Class<?> intf = method.getDeclaringClass(); 1365 // access check on the default method 1366 method.checkAccess(caller, intf, proxyClass, method.getModifiers()); 1367 } 1368 1369 MethodHandle mh = Proxy.defaultMethodHandle(proxyClass, method); 1370 // invoke the super method 1371 try { 1372 // the args array can be null if the number of formal parameters required by 1373 // the method is zero (consistent with Method::invoke) 1374 Object[] params = args != null ? args : Proxy.EMPTY_ARGS; 1375 return mh.invokeExact(proxy, params); 1376 } catch (ClassCastException | NullPointerException e) { 1377 throw new IllegalArgumentException(e.getMessage(), e); 1378 } catch (Proxy.InvocationException e) { 1379 // unwrap and throw the exception thrown by the default method 1380 throw e.getCause(); 1381 } 1382 } 1383 1384 /** 1385 * Internal exception type to wrap the exception thrown by the default method 1386 * so that it can distinguish CCE and NPE thrown due to the arguments 1387 * incompatible with the method signature. 1388 */ 1389 static class InvocationException extends ReflectiveOperationException { 1390 @java.io.Serial 1391 private static final long serialVersionUID = 0L; 1392 1393 InvocationException(Throwable cause) { 1394 super(cause); 1395 } 1396 1397 /** 1398 * Wraps given cause with InvocationException and throws it. 1399 */ 1400 static Object wrap(Throwable cause) throws InvocationException { 1401 throw new InvocationException(cause); 1402 } 1403 1404 @Stable 1405 static MethodHandle wrapMethodHandle; 1406 1407 static MethodHandle wrapMH() { 1408 MethodHandle mh = wrapMethodHandle; 1409 if (mh == null) { 1410 try { 1411 wrapMethodHandle = mh = MethodHandles.lookup().findStatic( 1412 InvocationException.class, 1413 "wrap", 1414 MethodType.methodType(Object.class, Throwable.class) 1415 ); 1416 } catch (NoSuchMethodException | IllegalAccessException e) { 1417 throw new InternalError(e); 1418 } 1419 } 1420 return mh; 1421 } 1422 } 1423 1424 }