< prev index next >

src/java.base/share/classes/java/lang/reflect/ProxyGenerator_v49.java

Print this page


   1 /*
   2  * Copyright (c) 1999, 2018, 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.io.ByteArrayOutputStream;
  29 import java.io.DataOutputStream;
  30 import java.io.File;
  31 import java.io.IOException;
  32 import java.io.OutputStream;
  33 import java.lang.reflect.Array;
  34 import java.lang.reflect.Method;
  35 import java.nio.file.Files;
  36 import java.nio.file.Path;
  37 import java.util.ArrayList;
  38 import java.util.HashMap;

  39 import java.util.LinkedList;
  40 import java.util.List;
  41 import java.util.ListIterator;
  42 import java.util.Map;
  43 import sun.security.action.GetBooleanAction;
  44 
  45 /**
  46  * ProxyGenerator contains the code to generate a dynamic proxy class
  47  * for the java.lang.reflect.Proxy API.
  48  *
  49  * The external interfaces to ProxyGenerator is the static
  50  * "generateProxyClass" method.
  51  *
  52  * @author      Peter Jones
  53  * @since       1.3
  54  */
  55 class ProxyGenerator {
  56     /*
  57      * In the comments below, "JVMS" refers to The Java Virtual Machine
  58      * Specification Second Edition and "JLS" refers to the original
  59      * version of The Java Language Specification, unless otherwise
  60      * specified.
  61      */
  62 
  63     /* generate 1.5-era class file version */
  64     private static final int CLASSFILE_MAJOR_VERSION = 49;
  65     private static final int CLASSFILE_MINOR_VERSION = 0;
  66 
  67     /*
  68      * beginning of constants copied from
  69      * sun.tools.java.RuntimeConstants (which no longer exists):
  70      */
  71 
  72     /* constant pool tags */
  73     private static final int CONSTANT_UTF8              = 1;
  74     private static final int CONSTANT_UNICODE           = 2;
  75     private static final int CONSTANT_INTEGER           = 3;


 302 //  private static final int opc_jsr_w                  = 201;
 303 
 304     // end of constants copied from sun.tools.java.RuntimeConstants
 305 
 306     /** name of the superclass of proxy classes */
 307     private static final String superclassName = "java/lang/reflect/Proxy";
 308 
 309     /** name of field for storing a proxy instance's invocation handler */
 310     private static final String handlerFieldName = "h";
 311 
 312     /** debugging flag for saving generated class files */
 313     private static final boolean saveGeneratedFiles =
 314         java.security.AccessController.doPrivileged(
 315             new GetBooleanAction(
 316                 "jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue();
 317 
 318     /**
 319      * Generate a public proxy class given a name and a list of proxy interfaces.
 320      */
 321     static byte[] generateProxyClass(final String name,
 322                                      Class<?>[] interfaces) {
 323         return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER));
 324     }
 325 
 326     /**
 327      * Generate a proxy class given a name and a list of proxy interfaces.
 328      *
 329      * @param name        the class name of the proxy class
 330      * @param interfaces  proxy interfaces
 331      * @param accessFlags access flags of the proxy class
 332     */
 333     static byte[] generateProxyClass(final String name,
 334                                      Class<?>[] interfaces,
 335                                      int accessFlags)
 336     {
 337         ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
 338         final byte[] classFile = gen.generateClassFile();
 339 
 340         if (saveGeneratedFiles) {
 341             java.security.AccessController.doPrivileged(
 342             new java.security.PrivilegedAction<Void>() {
 343                 public Void run() {
 344                     try {
 345                         int i = name.lastIndexOf('.');
 346                         Path path;
 347                         if (i > 0) {
 348                             Path dir = Path.of(name.substring(0, i).replace('.', File.separatorChar));
 349                             Files.createDirectories(dir);
 350                             path = dir.resolve(name.substring(i+1, name.length()) + ".class");
 351                         } else {
 352                             path = Path.of(name + ".class");
 353                         }
 354                         Files.write(path, classFile);
 355                         return null;
 356                     } catch (IOException e) {
 357                         throw new InternalError(


 366 
 367     /* preloaded Method objects for methods in java.lang.Object */
 368     private static Method hashCodeMethod;
 369     private static Method equalsMethod;
 370     private static Method toStringMethod;
 371     static {
 372         try {
 373             hashCodeMethod = Object.class.getMethod("hashCode");
 374             equalsMethod =
 375                 Object.class.getMethod("equals", new Class<?>[] { Object.class });
 376             toStringMethod = Object.class.getMethod("toString");
 377         } catch (NoSuchMethodException e) {
 378             throw new NoSuchMethodError(e.getMessage());
 379         }
 380     }
 381 
 382     /** name of proxy class */
 383     private String className;
 384 
 385     /** proxy interfaces */
 386     private Class<?>[] interfaces;
 387 
 388     /** proxy class access flags */
 389     private int accessFlags;
 390 
 391     /** constant pool of class being generated */
 392     private ConstantPool cp = new ConstantPool();
 393 
 394     /** FieldInfo struct for each field of generated class */
 395     private List<FieldInfo> fields = new ArrayList<>();
 396 
 397     /** MethodInfo struct for each method of generated class */
 398     private List<MethodInfo> methods = new ArrayList<>();
 399 
 400     /**
 401      * maps method signature string to list of ProxyMethod objects for
 402      * proxy methods with that signature
 403      */
 404     private Map<String, List<ProxyMethod>> proxyMethods = new HashMap<>();
 405 
 406     /** count of ProxyMethod objects added to proxyMethods */
 407     private int proxyMethodCount = 0;
 408 
 409     /**
 410      * Construct a ProxyGenerator to generate a proxy class with the
 411      * specified name and for the given interfaces.
 412      *
 413      * A ProxyGenerator object contains the state for the ongoing
 414      * generation of a particular proxy class.
 415      */
 416     private ProxyGenerator(String className, Class<?>[] interfaces, int accessFlags) {
 417         this.className = className;
 418         this.interfaces = interfaces;
 419         this.accessFlags = accessFlags;
 420     }
 421 
 422     /**
 423      * Generate a class file for the proxy class.  This method drives the
 424      * class file generation process.
 425      */
 426     private byte[] generateClassFile() {
 427 
 428         /* ============================================================
 429          * Step 1: Assemble ProxyMethod objects for all methods to
 430          * generate proxy dispatching code for.
 431          */
 432 
 433         /*
 434          * Record that proxy methods are needed for the hashCode, equals,
 435          * and toString methods of java.lang.Object.  This is done before
 436          * the methods from the proxy interfaces so that the methods from


 523              * Write all the items of the "ClassFile" structure.
 524              * See JVMS section 4.1.
 525              */
 526                                         // u4 magic;
 527             dout.writeInt(0xCAFEBABE);
 528                                         // u2 minor_version;
 529             dout.writeShort(CLASSFILE_MINOR_VERSION);
 530                                         // u2 major_version;
 531             dout.writeShort(CLASSFILE_MAJOR_VERSION);
 532 
 533             cp.write(dout);             // (write constant pool)
 534 
 535                                         // u2 access_flags;
 536             dout.writeShort(accessFlags);
 537                                         // u2 this_class;
 538             dout.writeShort(cp.getClass(dotToSlash(className)));
 539                                         // u2 super_class;
 540             dout.writeShort(cp.getClass(superclassName));
 541 
 542                                         // u2 interfaces_count;
 543             dout.writeShort(interfaces.length);
 544                                         // u2 interfaces[interfaces_count];
 545             for (Class<?> intf : interfaces) {
 546                 dout.writeShort(cp.getClass(
 547                     dotToSlash(intf.getName())));
 548             }
 549 
 550                                         // u2 fields_count;
 551             dout.writeShort(fields.size());
 552                                         // field_info fields[fields_count];
 553             for (FieldInfo f : fields) {
 554                 f.write(dout);
 555             }
 556 
 557                                         // u2 methods_count;
 558             dout.writeShort(methods.size());
 559                                         // method_info methods[methods_count];
 560             for (MethodInfo m : methods) {
 561                 m.write(dout);
 562             }
 563 


   1 /*
   2  * Copyright (c) 1999, 2019, 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.io.ByteArrayOutputStream;
  29 import java.io.DataOutputStream;
  30 import java.io.File;
  31 import java.io.IOException;
  32 import java.io.OutputStream;


  33 import java.nio.file.Files;
  34 import java.nio.file.Path;
  35 import java.util.ArrayList;
  36 import java.util.HashMap;
  37 import java.util.LinkedHashMap;
  38 import java.util.LinkedList;
  39 import java.util.List;
  40 import java.util.ListIterator;
  41 import java.util.Map;
  42 import sun.security.action.GetBooleanAction;
  43 
  44 /**
  45  * ProxyGenerator contains the code to generate a dynamic proxy class
  46  * for the java.lang.reflect.Proxy API.
  47  *
  48  * The external interfaces to ProxyGenerator is the static
  49  * "generateProxyClass" method.
  50  *
  51  * @author      Peter Jones
  52  * @since       1.3
  53  */
  54 class ProxyGenerator_v49 {
  55     /*
  56      * In the comments below, "JVMS" refers to The Java Virtual Machine
  57      * Specification Second Edition and "JLS" refers to the original
  58      * version of The Java Language Specification, unless otherwise
  59      * specified.
  60      */
  61 
  62     /* generate 1.5-era class file version */
  63     private static final int CLASSFILE_MAJOR_VERSION = 49;
  64     private static final int CLASSFILE_MINOR_VERSION = 0;
  65 
  66     /*
  67      * beginning of constants copied from
  68      * sun.tools.java.RuntimeConstants (which no longer exists):
  69      */
  70 
  71     /* constant pool tags */
  72     private static final int CONSTANT_UTF8              = 1;
  73     private static final int CONSTANT_UNICODE           = 2;
  74     private static final int CONSTANT_INTEGER           = 3;


 301 //  private static final int opc_jsr_w                  = 201;
 302 
 303     // end of constants copied from sun.tools.java.RuntimeConstants
 304 
 305     /** name of the superclass of proxy classes */
 306     private static final String superclassName = "java/lang/reflect/Proxy";
 307 
 308     /** name of field for storing a proxy instance's invocation handler */
 309     private static final String handlerFieldName = "h";
 310 
 311     /** debugging flag for saving generated class files */
 312     private static final boolean saveGeneratedFiles =
 313         java.security.AccessController.doPrivileged(
 314             new GetBooleanAction(
 315                 "jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue();
 316 
 317     /**
 318      * Generate a public proxy class given a name and a list of proxy interfaces.
 319      */
 320     static byte[] generateProxyClass(final String name,
 321                                      List<Class<?>> interfaces) {
 322         return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER));
 323     }
 324 
 325     /**
 326      * Generate a proxy class given a name and a list of proxy interfaces.
 327      *
 328      * @param name        the class name of the proxy class
 329      * @param interfaces  proxy interfaces
 330      * @param accessFlags access flags of the proxy class
 331     */
 332     static byte[] generateProxyClass(final String name,
 333                                      List<Class<?>> interfaces,
 334                                      int accessFlags)
 335     {
 336         ProxyGenerator_v49 gen = new ProxyGenerator_v49(name, interfaces, accessFlags);
 337         final byte[] classFile = gen.generateClassFile();
 338 
 339         if (saveGeneratedFiles) {
 340             java.security.AccessController.doPrivileged(
 341             new java.security.PrivilegedAction<Void>() {
 342                 public Void run() {
 343                     try {
 344                         int i = name.lastIndexOf('.');
 345                         Path path;
 346                         if (i > 0) {
 347                             Path dir = Path.of(name.substring(0, i).replace('.', File.separatorChar));
 348                             Files.createDirectories(dir);
 349                             path = dir.resolve(name.substring(i+1, name.length()) + ".class");
 350                         } else {
 351                             path = Path.of(name + ".class");
 352                         }
 353                         Files.write(path, classFile);
 354                         return null;
 355                     } catch (IOException e) {
 356                         throw new InternalError(


 365 
 366     /* preloaded Method objects for methods in java.lang.Object */
 367     private static Method hashCodeMethod;
 368     private static Method equalsMethod;
 369     private static Method toStringMethod;
 370     static {
 371         try {
 372             hashCodeMethod = Object.class.getMethod("hashCode");
 373             equalsMethod =
 374                 Object.class.getMethod("equals", new Class<?>[] { Object.class });
 375             toStringMethod = Object.class.getMethod("toString");
 376         } catch (NoSuchMethodException e) {
 377             throw new NoSuchMethodError(e.getMessage());
 378         }
 379     }
 380 
 381     /** name of proxy class */
 382     private String className;
 383 
 384     /** proxy interfaces */
 385     private List<Class<?>> interfaces;
 386 
 387     /** proxy class access flags */
 388     private int accessFlags;
 389 
 390     /** constant pool of class being generated */
 391     private ConstantPool cp = new ConstantPool();
 392 
 393     /** FieldInfo struct for each field of generated class */
 394     private List<FieldInfo> fields = new ArrayList<>();
 395 
 396     /** MethodInfo struct for each method of generated class */
 397     private List<MethodInfo> methods = new ArrayList<>();
 398 
 399     /**
 400      * maps method signature string to list of ProxyMethod objects for
 401      * proxy methods with that signature
 402      */
 403     private Map<String, List<ProxyMethod>> proxyMethods = new LinkedHashMap<>();
 404 
 405     /** count of ProxyMethod objects added to proxyMethods */
 406     private int proxyMethodCount = 0;
 407 
 408     /**
 409      * Construct a ProxyGenerator to generate a proxy class with the
 410      * specified name and for the given interfaces.
 411      *
 412      * A ProxyGenerator object contains the state for the ongoing
 413      * generation of a particular proxy class.
 414      */
 415     ProxyGenerator_v49(String className, List<Class<?>> interfaces, int accessFlags) {
 416         this.className = className;
 417         this.interfaces = interfaces;
 418         this.accessFlags = accessFlags;
 419     }
 420 
 421     /**
 422      * Generate a class file for the proxy class.  This method drives the
 423      * class file generation process.
 424      */
 425     private byte[] generateClassFile() {
 426 
 427         /* ============================================================
 428          * Step 1: Assemble ProxyMethod objects for all methods to
 429          * generate proxy dispatching code for.
 430          */
 431 
 432         /*
 433          * Record that proxy methods are needed for the hashCode, equals,
 434          * and toString methods of java.lang.Object.  This is done before
 435          * the methods from the proxy interfaces so that the methods from


 522              * Write all the items of the "ClassFile" structure.
 523              * See JVMS section 4.1.
 524              */
 525                                         // u4 magic;
 526             dout.writeInt(0xCAFEBABE);
 527                                         // u2 minor_version;
 528             dout.writeShort(CLASSFILE_MINOR_VERSION);
 529                                         // u2 major_version;
 530             dout.writeShort(CLASSFILE_MAJOR_VERSION);
 531 
 532             cp.write(dout);             // (write constant pool)
 533 
 534                                         // u2 access_flags;
 535             dout.writeShort(accessFlags);
 536                                         // u2 this_class;
 537             dout.writeShort(cp.getClass(dotToSlash(className)));
 538                                         // u2 super_class;
 539             dout.writeShort(cp.getClass(superclassName));
 540 
 541                                         // u2 interfaces_count;
 542             dout.writeShort(interfaces.size());
 543                                         // u2 interfaces[interfaces_count];
 544             for (Class<?> intf : interfaces) {
 545                 dout.writeShort(cp.getClass(
 546                     dotToSlash(intf.getName())));
 547             }
 548 
 549                                         // u2 fields_count;
 550             dout.writeShort(fields.size());
 551                                         // field_info fields[fields_count];
 552             for (FieldInfo f : fields) {
 553                 f.write(dout);
 554             }
 555 
 556                                         // u2 methods_count;
 557             dout.writeShort(methods.size());
 558                                         // method_info methods[methods_count];
 559             for (MethodInfo m : methods) {
 560                 m.write(dout);
 561             }
 562 


< prev index next >