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
|