jdk/src/share/classes/java/lang/reflect/Proxy.java

Print this page
rev 5671 : 7197546: (proxy) Reflect about creating reflective proxies
Reviewed-by: alanb, jdn, jrose


  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.ref.Reference;
  29 import java.lang.ref.WeakReference;



  30 import java.util.Arrays;
  31 import java.util.Collections;
  32 import java.util.HashMap;
  33 import java.util.HashSet;
  34 import java.util.Map;
  35 import java.util.Set;
  36 import java.util.List;
  37 import java.util.WeakHashMap;
  38 import sun.misc.ProxyGenerator;



  39 
  40 /**
  41  * {@code Proxy} provides static methods for creating dynamic proxy
  42  * classes and instances, and it is also the superclass of all
  43  * dynamic proxy classes created by those methods.
  44  *
  45  * <p>To create a proxy for some interface {@code Foo}:
  46  * <pre>
  47  *     InvocationHandler handler = new MyInvocationHandler(...);
  48  *     Class proxyClass = Proxy.getProxyClass(
  49  *         Foo.class.getClassLoader(), new Class[] { Foo.class });
  50  *     Foo f = (Foo) proxyClass.
  51  *         getConstructor(new Class[] { InvocationHandler.class }).
  52  *         newInstance(new Object[] { handler });
  53  * </pre>
  54  * or more simply:
  55  * <pre>
  56  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  57  *                                          new Class[] { Foo.class },
  58  *                                          handler);


 248     /**
 249      * the invocation handler for this proxy instance.
 250      * @serial
 251      */
 252     protected InvocationHandler h;
 253 
 254     /**
 255      * Prohibits instantiation.
 256      */
 257     private Proxy() {
 258     }
 259 
 260     /**
 261      * Constructs a new {@code Proxy} instance from a subclass
 262      * (typically, a dynamic proxy class) with the specified value
 263      * for its invocation handler.
 264      *
 265      * @param   h the invocation handler for this proxy instance
 266      */
 267     protected Proxy(InvocationHandler h) {

 268         this.h = h;
 269     }
 270 



























































 271     /**
 272      * Returns the {@code java.lang.Class} object for a proxy class
 273      * given a class loader and an array of interfaces.  The proxy class
 274      * will be defined by the specified class loader and will implement
 275      * all of the supplied interfaces.  If a proxy class for the same
 276      * permutation of interfaces has already been defined by the class
 277      * loader, then the existing proxy class will be returned; otherwise,
 278      * a proxy class for those interfaces will be generated dynamically
 279      * and defined by the class loader.
 280      *
 281      * <p>There are several restrictions on the parameters that may be
 282      * passed to {@code Proxy.getProxyClass}:
 283      *
 284      * <ul>
 285      * <li>All of the {@code Class} objects in the
 286      * {@code interfaces} array must represent interfaces, not
 287      * classes or primitive types.
 288      *
 289      * <li>No two elements in the {@code interfaces} array may
 290      * refer to identical {@code Class} objects.


 329      * <p>Note that the order of the specified proxy interfaces is
 330      * significant: two requests for a proxy class with the same combination
 331      * of interfaces but in a different order will result in two distinct
 332      * proxy classes.
 333      *
 334      * @param   loader the class loader to define the proxy class
 335      * @param   interfaces the list of interfaces for the proxy class
 336      *          to implement
 337      * @return  a proxy class that is defined in the specified class loader
 338      *          and that implements the specified interfaces
 339      * @throws  IllegalArgumentException if any of the restrictions on the
 340      *          parameters that may be passed to {@code getProxyClass}
 341      *          are violated
 342      * @throws  NullPointerException if the {@code interfaces} array
 343      *          argument or any of its elements are {@code null}
 344      */
 345     public static Class<?> getProxyClass(ClassLoader loader,
 346                                          Class<?>... interfaces)
 347         throws IllegalArgumentException
 348     {













































 349         if (interfaces.length > 65535) {
 350             throw new IllegalArgumentException("interface limit exceeded");
 351         }
 352 
 353         Class<?> proxyClass = null;
 354 
 355         /* collect interface names to use as key for proxy class cache */
 356         String[] interfaceNames = new String[interfaces.length];
 357 
 358         // for detecting duplicates
 359         Set<Class<?>> interfaceSet = new HashSet<>();
 360 
 361         for (int i = 0; i < interfaces.length; i++) {
 362             /*
 363              * Verify that the class loader resolves the name of this
 364              * interface to the same Class object.
 365              */
 366             String interfaceName = interfaces[i].getName();
 367             Class<?> interfaceClass = null;
 368             try {


 480             /*
 481              * Record the package of a non-public proxy interface so that the
 482              * proxy class will be defined in the same package.  Verify that
 483              * all non-public proxy interfaces are in the same package.
 484              */
 485             for (int i = 0; i < interfaces.length; i++) {
 486                 int flags = interfaces[i].getModifiers();
 487                 if (!Modifier.isPublic(flags)) {
 488                     String name = interfaces[i].getName();
 489                     int n = name.lastIndexOf('.');
 490                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
 491                     if (proxyPkg == null) {
 492                         proxyPkg = pkg;
 493                     } else if (!pkg.equals(proxyPkg)) {
 494                         throw new IllegalArgumentException(
 495                             "non-public interfaces from different packages");
 496                     }
 497                 }
 498             }
 499 
 500             if (proxyPkg == null) {     // if no non-public proxy interfaces,
 501                 proxyPkg = "";          // use the unnamed package

 502             }
 503 
 504             {
 505                 /*
 506                  * Choose a name for the proxy class to generate.
 507                  */
 508                 long num;
 509                 synchronized (nextUniqueNumberLock) {
 510                     num = nextUniqueNumber++;
 511                 }
 512                 String proxyName = proxyPkg + proxyClassNamePrefix + num;
 513                 /*
 514                  * Verify that the class loader hasn't already
 515                  * defined a class with the chosen name.
 516                  */
 517 
 518                 /*
 519                  * Generate the specified proxy class.
 520                  */
 521                 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(


 581      * @throws  IllegalArgumentException if any of the restrictions on the
 582      *          parameters that may be passed to {@code getProxyClass}
 583      *          are violated
 584      * @throws  NullPointerException if the {@code interfaces} array
 585      *          argument or any of its elements are {@code null}, or
 586      *          if the invocation handler, {@code h}, is
 587      *          {@code null}
 588      */
 589     public static Object newProxyInstance(ClassLoader loader,
 590                                           Class<?>[] interfaces,
 591                                           InvocationHandler h)
 592         throws IllegalArgumentException
 593     {
 594         if (h == null) {
 595             throw new NullPointerException();
 596         }
 597 
 598         /*
 599          * Look up or generate the designated proxy class.
 600          */
 601         Class<?> cl = getProxyClass(loader, interfaces);
 602 
 603         /*
 604          * Invoke its constructor with the designated invocation handler.
 605          */
 606         try {
 607             Constructor cons = cl.getConstructor(constructorParams);
 608             return cons.newInstance(new Object[] { h });












 609         } catch (NoSuchMethodException e) {
 610             throw new InternalError(e.toString());
 611         } catch (IllegalAccessException e) {
 612             throw new InternalError(e.toString());
 613         } catch (InstantiationException e) {




 614             throw new InternalError(e.toString());
 615         } catch (InvocationTargetException e) {
 616             throw new InternalError(e.toString());





 617         }
 618     }
 619 
 620     /**
 621      * Returns true if and only if the specified class was dynamically
 622      * generated to be a proxy class using the {@code getProxyClass}
 623      * method or the {@code newProxyInstance} method.
 624      *
 625      * <p>The reliability of this method is important for the ability
 626      * to use it to make security decisions, so its implementation should
 627      * not just test if the class in question extends {@code Proxy}.
 628      *
 629      * @param   cl the class to test
 630      * @return  {@code true} if the class is a proxy class and
 631      *          {@code false} otherwise
 632      * @throws  NullPointerException if {@code cl} is {@code null}
 633      */
 634     public static boolean isProxyClass(Class<?> cl) {
 635         if (cl == null) {
 636             throw new NullPointerException();




  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.ref.Reference;
  29 import java.lang.ref.WeakReference;
  30 import java.security.AccessController;
  31 import java.security.Permission;
  32 import java.security.PrivilegedAction;
  33 import java.util.Arrays;
  34 import java.util.Collections;
  35 import java.util.HashMap;
  36 import java.util.HashSet;
  37 import java.util.Map;
  38 import java.util.Set;
  39 import java.util.List;
  40 import java.util.WeakHashMap;
  41 import sun.misc.ProxyGenerator;
  42 import sun.reflect.Reflection;
  43 import sun.reflect.misc.ReflectUtil;
  44 import sun.security.util.SecurityConstants;
  45 
  46 /**
  47  * {@code Proxy} provides static methods for creating dynamic proxy
  48  * classes and instances, and it is also the superclass of all
  49  * dynamic proxy classes created by those methods.
  50  *
  51  * <p>To create a proxy for some interface {@code Foo}:
  52  * <pre>
  53  *     InvocationHandler handler = new MyInvocationHandler(...);
  54  *     Class proxyClass = Proxy.getProxyClass(
  55  *         Foo.class.getClassLoader(), new Class[] { Foo.class });
  56  *     Foo f = (Foo) proxyClass.
  57  *         getConstructor(new Class[] { InvocationHandler.class }).
  58  *         newInstance(new Object[] { handler });
  59  * </pre>
  60  * or more simply:
  61  * <pre>
  62  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  63  *                                          new Class[] { Foo.class },
  64  *                                          handler);


 254     /**
 255      * the invocation handler for this proxy instance.
 256      * @serial
 257      */
 258     protected InvocationHandler h;
 259 
 260     /**
 261      * Prohibits instantiation.
 262      */
 263     private Proxy() {
 264     }
 265 
 266     /**
 267      * Constructs a new {@code Proxy} instance from a subclass
 268      * (typically, a dynamic proxy class) with the specified value
 269      * for its invocation handler.
 270      *
 271      * @param   h the invocation handler for this proxy instance
 272      */
 273     protected Proxy(InvocationHandler h) {
 274         doNewInstanceCheck();
 275         this.h = h;
 276     }
 277 
 278     private static class ProxyAccessHelper {
 279         // The permission is implementation specific.
 280         static final Permission PROXY_PERMISSION =
 281             new ReflectPermission("proxyConstructorNewInstance");
 282         // These system properties are defined to provide a short-term
 283         // workaround if customers need to disable the new security checks.
 284         static final boolean allowNewInstance;
 285         static final boolean allowNullLoader;
 286         static {
 287             allowNewInstance = getBooleanProperty("sun.reflect.proxy.allowsNewInstance");
 288             allowNullLoader = getBooleanProperty("sun.reflect.proxy.allowsNullLoader");
 289         }
 290 
 291         private static boolean getBooleanProperty(final String key) {
 292             String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
 293                 public String run() {
 294                     return System.getProperty(key);
 295                 }
 296             });
 297             return Boolean.valueOf(s);
 298         }
 299 
 300         static boolean needsNewInstanceCheck(Class<?> proxyClass) {
 301             if (!Proxy.isProxyClass(proxyClass) || allowNewInstance) {
 302                 return false;
 303             }
 304 
 305             if (proxyClass.getName().startsWith(ReflectUtil.PROXY_PACKAGE + ".")) {
 306                 // all proxy interfaces are public
 307                 return false;
 308             }
 309             for (Class<?> intf : proxyClass.getInterfaces()) {
 310                 if (!Modifier.isPublic(intf.getModifiers())) {
 311                     return true;
 312                 }
 313             }
 314             return false;
 315         }
 316     }
 317 
 318     /*
 319      * Access check on a proxy class that implements any non-public interface.
 320      *
 321      * @throws  SecurityException if a security manager exists, and
 322      *          the caller does not have the permission.
 323      */
 324     private void doNewInstanceCheck() {
 325         SecurityManager sm = System.getSecurityManager();
 326         Class<?> proxyClass = this.getClass();
 327         if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(proxyClass)) {
 328             try {
 329                 sm.checkPermission(ProxyAccessHelper.PROXY_PERMISSION);
 330             } catch (SecurityException e) {
 331                 throw new SecurityException("Not allowed to construct a Proxy "
 332                         + "instance that implements a non-public interface", e);
 333             }
 334         }
 335     }
 336 
 337     /**
 338      * Returns the {@code java.lang.Class} object for a proxy class
 339      * given a class loader and an array of interfaces.  The proxy class
 340      * will be defined by the specified class loader and will implement
 341      * all of the supplied interfaces.  If a proxy class for the same
 342      * permutation of interfaces has already been defined by the class
 343      * loader, then the existing proxy class will be returned; otherwise,
 344      * a proxy class for those interfaces will be generated dynamically
 345      * and defined by the class loader.
 346      *
 347      * <p>There are several restrictions on the parameters that may be
 348      * passed to {@code Proxy.getProxyClass}:
 349      *
 350      * <ul>
 351      * <li>All of the {@code Class} objects in the
 352      * {@code interfaces} array must represent interfaces, not
 353      * classes or primitive types.
 354      *
 355      * <li>No two elements in the {@code interfaces} array may
 356      * refer to identical {@code Class} objects.


 395      * <p>Note that the order of the specified proxy interfaces is
 396      * significant: two requests for a proxy class with the same combination
 397      * of interfaces but in a different order will result in two distinct
 398      * proxy classes.
 399      *
 400      * @param   loader the class loader to define the proxy class
 401      * @param   interfaces the list of interfaces for the proxy class
 402      *          to implement
 403      * @return  a proxy class that is defined in the specified class loader
 404      *          and that implements the specified interfaces
 405      * @throws  IllegalArgumentException if any of the restrictions on the
 406      *          parameters that may be passed to {@code getProxyClass}
 407      *          are violated
 408      * @throws  NullPointerException if the {@code interfaces} array
 409      *          argument or any of its elements are {@code null}
 410      */
 411     public static Class<?> getProxyClass(ClassLoader loader,
 412                                          Class<?>... interfaces)
 413         throws IllegalArgumentException
 414     {
 415         return getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
 416     }
 417 
 418     private static void checkProxyLoader(ClassLoader ccl,
 419                                          ClassLoader loader)
 420     {
 421         SecurityManager sm = System.getSecurityManager();
 422         if (sm != null) {
 423             if (loader == null && ccl != null) {
 424                 if (!ProxyAccessHelper.allowNullLoader) {
 425                     sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
 426                 }
 427             }
 428         }
 429     }
 430 
 431     /*
 432      * Generate a proxy class (caller-sensitive).
 433      *
 434      * To define a proxy class, it performs the access checks as in
 435      * Class.forName (VM will invoke ClassLoader.checkPackageAccess):
 436      * 1. "getClassLoader" permission check if loader == null
 437      * 2. checkPackageAccess on the interfaces it implements
 438      *
 439      * To get a constructor and new instance of a proxy class, it performs
 440      * the package access check on the interfaces it implements
 441      * as in Class.getConstructor.
 442      *
 443      * If an interface is non-public, the proxy class must be defined by
 444      * the defining loader of the interface.  If the caller's class loader
 445      * is not the same as the defining loader of the interface, the VM
 446      * will throw IllegalAccessError when the generated proxy class is
 447      * being defined via the defineClass0 method.
 448      */
 449     private static Class<?> getProxyClass0(ClassLoader loader,
 450                                            Class<?>... interfaces) {
 451         SecurityManager sm = System.getSecurityManager();
 452         if (sm != null) {
 453             final int CALLER_FRAME = 3; // 0: Reflection, 1: getProxyClass0 2: Proxy 3: caller
 454             final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME);
 455             final ClassLoader ccl = caller.getClassLoader();
 456             checkProxyLoader(ccl, loader);
 457             ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
 458         }
 459 
 460         if (interfaces.length > 65535) {
 461             throw new IllegalArgumentException("interface limit exceeded");
 462         }
 463 
 464         Class<?> proxyClass = null;
 465 
 466         /* collect interface names to use as key for proxy class cache */
 467         String[] interfaceNames = new String[interfaces.length];
 468 
 469         // for detecting duplicates
 470         Set<Class<?>> interfaceSet = new HashSet<>();
 471 
 472         for (int i = 0; i < interfaces.length; i++) {
 473             /*
 474              * Verify that the class loader resolves the name of this
 475              * interface to the same Class object.
 476              */
 477             String interfaceName = interfaces[i].getName();
 478             Class<?> interfaceClass = null;
 479             try {


 591             /*
 592              * Record the package of a non-public proxy interface so that the
 593              * proxy class will be defined in the same package.  Verify that
 594              * all non-public proxy interfaces are in the same package.
 595              */
 596             for (int i = 0; i < interfaces.length; i++) {
 597                 int flags = interfaces[i].getModifiers();
 598                 if (!Modifier.isPublic(flags)) {
 599                     String name = interfaces[i].getName();
 600                     int n = name.lastIndexOf('.');
 601                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
 602                     if (proxyPkg == null) {
 603                         proxyPkg = pkg;
 604                     } else if (!pkg.equals(proxyPkg)) {
 605                         throw new IllegalArgumentException(
 606                             "non-public interfaces from different packages");
 607                     }
 608                 }
 609             }
 610 
 611             if (proxyPkg == null) {
 612                 // if no non-public proxy interfaces, use sun.proxy package
 613                 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
 614             }
 615 
 616             {
 617                 /*
 618                  * Choose a name for the proxy class to generate.
 619                  */
 620                 long num;
 621                 synchronized (nextUniqueNumberLock) {
 622                     num = nextUniqueNumber++;
 623                 }
 624                 String proxyName = proxyPkg + proxyClassNamePrefix + num;
 625                 /*
 626                  * Verify that the class loader hasn't already
 627                  * defined a class with the chosen name.
 628                  */
 629 
 630                 /*
 631                  * Generate the specified proxy class.
 632                  */
 633                 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(


 693      * @throws  IllegalArgumentException if any of the restrictions on the
 694      *          parameters that may be passed to {@code getProxyClass}
 695      *          are violated
 696      * @throws  NullPointerException if the {@code interfaces} array
 697      *          argument or any of its elements are {@code null}, or
 698      *          if the invocation handler, {@code h}, is
 699      *          {@code null}
 700      */
 701     public static Object newProxyInstance(ClassLoader loader,
 702                                           Class<?>[] interfaces,
 703                                           InvocationHandler h)
 704         throws IllegalArgumentException
 705     {
 706         if (h == null) {
 707             throw new NullPointerException();
 708         }
 709 
 710         /*
 711          * Look up or generate the designated proxy class.
 712          */
 713         Class<?> cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
 714 
 715         /*
 716          * Invoke its constructor with the designated invocation handler.
 717          */
 718         try {
 719             final Constructor<?> cons = cl.getConstructor(constructorParams);
 720             final InvocationHandler ih = h;
 721             SecurityManager sm = System.getSecurityManager();
 722             if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
 723                 // create proxy instance with doPrivilege as the proxy class may
 724                 // implement non-public interfaces that requires a special permission
 725                 return AccessController.doPrivileged(new PrivilegedAction<Object>() {
 726                     public Object run() {
 727                         return newInstance(cons, ih);
 728                     }
 729                 });
 730             } else {
 731                 return newInstance(cons, ih);
 732             }
 733         } catch (NoSuchMethodException e) {
 734             throw new InternalError(e.toString());
 735         }
 736     }
 737 
 738     private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
 739         try {
 740             return cons.newInstance(new Object[] {h} );
 741         } catch (IllegalAccessException | InstantiationException e) {
 742             throw new InternalError(e.toString());
 743         } catch (InvocationTargetException e) {
 744             Throwable t = e.getCause();
 745             if (t instanceof RuntimeException) {
 746                 throw (RuntimeException) t;
 747             } else {
 748                 throw new InternalError(t.toString());
 749             }
 750         }
 751     }
 752 
 753     /**
 754      * Returns true if and only if the specified class was dynamically
 755      * generated to be a proxy class using the {@code getProxyClass}
 756      * method or the {@code newProxyInstance} method.
 757      *
 758      * <p>The reliability of this method is important for the ability
 759      * to use it to make security decisions, so its implementation should
 760      * not just test if the class in question extends {@code Proxy}.
 761      *
 762      * @param   cl the class to test
 763      * @return  {@code true} if the class is a proxy class and
 764      *          {@code false} otherwise
 765      * @throws  NullPointerException if {@code cl} is {@code null}
 766      */
 767     public static boolean isProxyClass(Class<?> cl) {
 768         if (cl == null) {
 769             throw new NullPointerException();