Since it is a BCEL tutorial, get the BCEL library first from here
Manipulating java byte code directly is not trivial in nature, so I decided to break the tutorial into a series. This one is the first - the hello world. Keep in touch to learn more.
Structure of Java Class File: As with any file format, java class file also has a format. The class file format is as shown below. It gives the overall structure of the whole class. This is picked up directly from the JVM specification.
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
The first question now would be what are u2, u4 etc. u2 is an unsigned integer of 2 bytes, and of course u4 is an unsigned integer of 4 bytes. cp_info, field_info etc. are complex structures of variable length. I will cover their details in the following.
magic: Magic is a four byte integer with a fixed value. It distinguishes other kinds of files from class files. Its value is always 0xCAFEBABE.
minor_version, major_version: pair of two byte integers giving the version information. The minor and major version must fall in a range for the JVM to load the class.
constant_pool: Is a store for all the constants used in the class. The constant pool stores every constant including the class name, method name, field name, super class name, class references etc. It also stores all the constants used in the class as literals. This is in most cases the biggest section in the class file.
access_flags: These are all the access flags of the class. The access flag field is a two byte integer with specific bits assigned as specific flags representing whether the class is public, whether the class is final, whether it is an interface etc.
this_class: Information about this class.
super_class: Information about this class.
interfaces: List of all interfaces the class implements.
fields: List of all fields in this class.
methods: List of all methods in this class.
attributes: Stores whether the class is deprecated and if the class has a source file.
That's it. Now we will look into a little detail about how the constant pool, fields and methods are stored. We would not have to concentrate on every detail of the bit patterns used to store these, as BCEL will take care of them. So, only an overall understanding will suffice.
But, before we dive in, let us look a very simple program written using BCEL to get a description of the class. I will also use the output of this program to clarify the understanding. I have only concentrated on constant pool, fields and methods. This program shows how easily we can access the details of the class with BCEL.
package com.geekyarticles.bcel;
import java.io.IOException;
import java.util.Arrays;
import org.apache.bcel.classfile.ClassFormatException;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
public class DisplayDetails {
private static int sampleField;
/**
* @param args
* @throws IOException
* @throws ClassFormatException
*/
public static void main(String[] args) throws ClassFormatException, IOException {
/*An existing class can be parsed with ClassParser */
ClassParser parser=new ClassParser(DisplayDetails.class.getResourceAsStream("/com/geekyarticles/bcel/DisplayDetails.class"), "DisplayDetails.class");
JavaClass javaClass=parser.parse();
System.out.println("*******Constant Pool*********");
System.out.println(javaClass.getConstantPool());
System.out.println("*******Fields*********");
System.out.println(Arrays.toString(javaClass.getFields()));
System.out.println();
System.out.println("*******Methods*********");
System.out.println(Arrays.toString(javaClass.getMethods()));
for(Method method:javaClass.getMethods()){
System.out.println(method);
System.out.println(method.getCode());
}
}
}
import java.io.IOException;
import java.util.Arrays;
import org.apache.bcel.classfile.ClassFormatException;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
public class DisplayDetails {
private static int sampleField;
/**
* @param args
* @throws IOException
* @throws ClassFormatException
*/
public static void main(String[] args) throws ClassFormatException, IOException {
/*An existing class can be parsed with ClassParser */
ClassParser parser=new ClassParser(DisplayDetails.class.getResourceAsStream("/com/geekyarticles/bcel/DisplayDetails.class"), "DisplayDetails.class");
JavaClass javaClass=parser.parse();
System.out.println("*******Constant Pool*********");
System.out.println(javaClass.getConstantPool());
System.out.println("*******Fields*********");
System.out.println(Arrays.toString(javaClass.getFields()));
System.out.println();
System.out.println("*******Methods*********");
System.out.println(Arrays.toString(javaClass.getMethods()));
for(Method method:javaClass.getMethods()){
System.out.println(method);
System.out.println(method.getCode());
}
}
}
*******Constant Pool*********
1)CONSTANT_Class[7](name_index = 2)
2)CONSTANT_Utf8[1]("com/geekyarticles/bcel/DisplayDetails")
3)CONSTANT_Class[7](name_index = 4)
4)CONSTANT_Utf8[1]("java/lang/Object")
5)CONSTANT_Utf8[1]("sampleField")
6)CONSTANT_Utf8[1]("I")
7)CONSTANT_Utf8[1]("<init>")
8)CONSTANT_Utf8[1]("()V")
9)CONSTANT_Utf8[1]("Code")
10)CONSTANT_Methodref[10](class_index = 3, name_and_type_index = 11)
11)CONSTANT_NameAndType[12](name_index = 7, signature_index = 8)
12)CONSTANT_Utf8[1]("LineNumberTable")
13)CONSTANT_Utf8[1]("LocalVariableTable")
14)CONSTANT_Utf8[1]("this")
15)CONSTANT_Utf8[1]("Lcom/geekyarticles/bcel/DisplayDetails;")
16)CONSTANT_Utf8[1]("main")
17)CONSTANT_Utf8[1]("([Ljava/lang/String;)V")
18)CONSTANT_Utf8[1]("Exceptions")
19)CONSTANT_Class[7](name_index = 20)
20)CONSTANT_Utf8[1]("org/apache/bcel/classfile/ClassFormatException")
21)CONSTANT_Class[7](name_index = 22)
22)CONSTANT_Utf8[1]("java/io/IOException")
23)CONSTANT_Class[7](name_index = 24)
24)CONSTANT_Utf8[1]("org/apache/bcel/classfile/ClassParser")
25)CONSTANT_String[8](string_index = 26)
26)CONSTANT_Utf8[1]("/com/geekyarticles/bcel/DisplayDetails.class")
27)CONSTANT_Methodref[10](class_index = 28, name_and_type_index = 30)
28)CONSTANT_Class[7](name_index = 29)
29)CONSTANT_Utf8[1]("java/lang/Class")
30)CONSTANT_NameAndType[12](name_index = 31, signature_index = 32)
31)CONSTANT_Utf8[1]("getResourceAsStream")
32)CONSTANT_Utf8[1]("(Ljava/lang/String;)Ljava/io/InputStream;")
33)CONSTANT_String[8](string_index = 34)
34)CONSTANT_Utf8[1]("DisplayDetails.class")
35)CONSTANT_Methodref[10](class_index = 23, name_and_type_index = 36)
36)CONSTANT_NameAndType[12](name_index = 7, signature_index = 37)
37)CONSTANT_Utf8[1]("(Ljava/io/InputStream;Ljava/lang/String;)V")
38)CONSTANT_Methodref[10](class_index = 23, name_and_type_index = 39)
39)CONSTANT_NameAndType[12](name_index = 40, signature_index = 41)
40)CONSTANT_Utf8[1]("parse")
41)CONSTANT_Utf8[1]("()Lorg/apache/bcel/classfile/JavaClass;")
42)CONSTANT_Fieldref[9](class_index = 43, name_and_type_index = 45)
43)CONSTANT_Class[7](name_index = 44)
44)CONSTANT_Utf8[1]("java/lang/System")
45)CONSTANT_NameAndType[12](name_index = 46, signature_index = 47)
46)CONSTANT_Utf8[1]("out")
47)CONSTANT_Utf8[1]("Ljava/io/PrintStream;")
48)CONSTANT_String[8](string_index = 49)
49)CONSTANT_Utf8[1]("*******Constant Pool*********")
50)CONSTANT_Methodref[10](class_index = 51, name_and_type_index = 53)
51)CONSTANT_Class[7](name_index = 52)
52)CONSTANT_Utf8[1]("java/io/PrintStream")
53)CONSTANT_NameAndType[12](name_index = 54, signature_index = 55)
54)CONSTANT_Utf8[1]("println")
55)CONSTANT_Utf8[1]("(Ljava/lang/String;)V")
56)CONSTANT_Methodref[10](class_index = 57, name_and_type_index = 59)
57)CONSTANT_Class[7](name_index = 58)
58)CONSTANT_Utf8[1]("org/apache/bcel/classfile/JavaClass")
59)CONSTANT_NameAndType[12](name_index = 60, signature_index = 61)
60)CONSTANT_Utf8[1]("getConstantPool")
61)CONSTANT_Utf8[1]("()Lorg/apache/bcel/classfile/ConstantPool;")
62)CONSTANT_Methodref[10](class_index = 51, name_and_type_index = 63)
63)CONSTANT_NameAndType[12](name_index = 54, signature_index = 64)
64)CONSTANT_Utf8[1]("(Ljava/lang/Object;)V")
65)CONSTANT_String[8](string_index = 66)
66)CONSTANT_Utf8[1]("*******Fields*********")
67)CONSTANT_Methodref[10](class_index = 57, name_and_type_index = 68)
68)CONSTANT_NameAndType[12](name_index = 69, signature_index = 70)
69)CONSTANT_Utf8[1]("getFields")
70)CONSTANT_Utf8[1]("()[Lorg/apache/bcel/classfile/Field;")
71)CONSTANT_Methodref[10](class_index = 72, name_and_type_index = 74)
72)CONSTANT_Class[7](name_index = 73)
73)CONSTANT_Utf8[1]("java/util/Arrays")
74)CONSTANT_NameAndType[12](name_index = 75, signature_index = 76)
75)CONSTANT_Utf8[1]("toString")
76)CONSTANT_Utf8[1]("([Ljava/lang/Object;)Ljava/lang/String;")
77)CONSTANT_Methodref[10](class_index = 51, name_and_type_index = 78)
78)CONSTANT_NameAndType[12](name_index = 54, signature_index = 8)
79)CONSTANT_String[8](string_index = 80)
80)CONSTANT_Utf8[1]("*******Methods*********")
81)CONSTANT_Methodref[10](class_index = 57, name_and_type_index = 82)
82)CONSTANT_NameAndType[12](name_index = 83, signature_index = 84)
83)CONSTANT_Utf8[1]("getMethods")
84)CONSTANT_Utf8[1]("()[Lorg/apache/bcel/classfile/Method;")
85)CONSTANT_Methodref[10](class_index = 86, name_and_type_index = 88)
86)CONSTANT_Class[7](name_index = 87)
87)CONSTANT_Utf8[1]("org/apache/bcel/classfile/Method")
88)CONSTANT_NameAndType[12](name_index = 89, signature_index = 90)
89)CONSTANT_Utf8[1]("getCode")
90)CONSTANT_Utf8[1]("()Lorg/apache/bcel/classfile/Code;")
91)CONSTANT_Utf8[1]("args")
92)CONSTANT_Utf8[1]("[Ljava/lang/String;")
93)CONSTANT_Utf8[1]("parser")
94)CONSTANT_Utf8[1]("Lorg/apache/bcel/classfile/ClassParser;")
95)CONSTANT_Utf8[1]("javaClass")
96)CONSTANT_Utf8[1]("Lorg/apache/bcel/classfile/JavaClass;")
97)CONSTANT_Utf8[1]("method")
98)CONSTANT_Utf8[1]("Lorg/apache/bcel/classfile/Method;")
99)CONSTANT_Utf8[1]("StackMapTable")
100)CONSTANT_Class[7](name_index = 92)
101)CONSTANT_Class[7](name_index = 102)
102)CONSTANT_Utf8[1]("[Lorg/apache/bcel/classfile/Method;")
103)CONSTANT_Utf8[1]("SourceFile")
104)CONSTANT_Utf8[1]("DisplayDetails.java")
*******Fields*********
[private static int sampleField]
*******Methods*********
[public void <init>(), public static void main(String[] args)
throws org.apache.bcel.classfile.ClassFormatException, java.io.IOException]
public void <init>()
Code(max_stack = 1, max_locals = 1, code_length = 5)
0: aload_0
1: invokespecial java.lang.Object.<init> ()V (10)
4: return
Attribute(s) =
LineNumber(0, 11)
LocalVariable(start_pc = 0, length = 5, index = 0:com.geekyarticles.bcel.DisplayDetails this)
public static void main(String[] args)
throws org.apache.bcel.classfile.ClassFormatException, java.io.IOException
Code(max_stack = 4, max_locals = 7, code_length = 138)
0: new <org.apache.bcel.classfile.ClassParser> (23)
3: dup
4: ldc com.geekyarticles.bcel.DisplayDetails (1)
6: ldc "/com/geekyarticles/bcel/DisplayDetails.class" (25)
8: invokevirtual java.lang.Class.getResourceAsStream (Ljava/lang/String;)Ljava/io/InputStream; (27)
11: ldc "DisplayDetails.class" (33)
13: invokespecial org.apache.bcel.classfile.ClassParser.<init> (Ljava/io/InputStream;Ljava/lang/String;)V (35)
16: astore_1
17: aload_1
18: invokevirtual org.apache.bcel.classfile.ClassParser.parse ()Lorg/apache/bcel/classfile/JavaClass; (38)
21: astore_2
22: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
25: ldc "*******Constant Pool*********" (48)
27: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (50)
30: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
33: aload_2
34: invokevirtual org.apache.bcel.classfile.JavaClass.getConstantPool ()Lorg/apache/bcel/classfile/ConstantPool; (56)
37: invokevirtual java.io.PrintStream.println (Ljava/lang/Object;)V (62)
40: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
43: ldc "*******Fields*********" (65)
45: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (50)
48: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
51: aload_2
52: invokevirtual org.apache.bcel.classfile.JavaClass.getFields ()[Lorg/apache/bcel/classfile/Field; (67)
55: invokestatic java.util.Arrays.toString ([Ljava/lang/Object;)Ljava/lang/String; (71)
58: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (50)
61: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
64: invokevirtual java.io.PrintStream.println ()V (77)
67: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
70: ldc "*******Methods*********" (79)
72: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (50)
75: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
78: aload_2
79: invokevirtual org.apache.bcel.classfile.JavaClass.getMethods ()[Lorg/apache/bcel/classfile/Method; (81)
82: invokestatic java.util.Arrays.toString ([Ljava/lang/Object;)Ljava/lang/String; (71)
85: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (50)
88: aload_2
89: invokevirtual org.apache.bcel.classfile.JavaClass.getMethods ()[Lorg/apache/bcel/classfile/Method; (81)
92: dup
93: astore %6
95: arraylength
96: istore %5
98: iconst_0
99: istore %4
101: goto #130
104: aload %6
106: iload %4
108: aaload
109: astore_3
110: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
113: aload_3
114: invokevirtual java.io.PrintStream.println (Ljava/lang/Object;)V (62)
117: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
120: aload_3
121: invokevirtual org.apache.bcel.classfile.Method.getCode ()Lorg/apache/bcel/classfile/Code; (85)
124: invokevirtual java.io.PrintStream.println (Ljava/lang/Object;)V (62)
127: iinc %4 1
130: iload %4
132: iload %5
134: if_icmplt #104
137: return
Attribute(s) =
LineNumber(0, 21), LineNumber(17, 22), LineNumber(22, 24), LineNumber(30, 25),
LineNumber(40, 27), LineNumber(48, 28), LineNumber(61, 29), LineNumber(67, 31),
LineNumber(75, 32), LineNumber(88, 34), LineNumber(110, 35), LineNumber(117, 36),
LineNumber(127, 34), LineNumber(137, 38)
LocalVariable(start_pc = 0, length = 138, index = 0:String[] args)
LocalVariable(start_pc = 17, length = 121, index = 1:org.apache.bcel.classfile.ClassParser parser)
LocalVariable(start_pc = 22, length = 116, index = 2:org.apache.bcel.classfile.JavaClass javaClass)
LocalVariable(start_pc = 110, length = 17, index = 3:org.apache.bcel.classfile.Method method)
(Unknown attribute StackMapTable: 00 02 ff 00 68 00 07 07 00 64... (truncated))
1)CONSTANT_Class[7](name_index = 2)
2)CONSTANT_Utf8[1]("com/geekyarticles/bcel/DisplayDetails")
3)CONSTANT_Class[7](name_index = 4)
4)CONSTANT_Utf8[1]("java/lang/Object")
5)CONSTANT_Utf8[1]("sampleField")
6)CONSTANT_Utf8[1]("I")
7)CONSTANT_Utf8[1]("<init>")
8)CONSTANT_Utf8[1]("()V")
9)CONSTANT_Utf8[1]("Code")
10)CONSTANT_Methodref[10](class_index = 3, name_and_type_index = 11)
11)CONSTANT_NameAndType[12](name_index = 7, signature_index = 8)
12)CONSTANT_Utf8[1]("LineNumberTable")
13)CONSTANT_Utf8[1]("LocalVariableTable")
14)CONSTANT_Utf8[1]("this")
15)CONSTANT_Utf8[1]("Lcom/geekyarticles/bcel/DisplayDetails;")
16)CONSTANT_Utf8[1]("main")
17)CONSTANT_Utf8[1]("([Ljava/lang/String;)V")
18)CONSTANT_Utf8[1]("Exceptions")
19)CONSTANT_Class[7](name_index = 20)
20)CONSTANT_Utf8[1]("org/apache/bcel/classfile/ClassFormatException")
21)CONSTANT_Class[7](name_index = 22)
22)CONSTANT_Utf8[1]("java/io/IOException")
23)CONSTANT_Class[7](name_index = 24)
24)CONSTANT_Utf8[1]("org/apache/bcel/classfile/ClassParser")
25)CONSTANT_String[8](string_index = 26)
26)CONSTANT_Utf8[1]("/com/geekyarticles/bcel/DisplayDetails.class")
27)CONSTANT_Methodref[10](class_index = 28, name_and_type_index = 30)
28)CONSTANT_Class[7](name_index = 29)
29)CONSTANT_Utf8[1]("java/lang/Class")
30)CONSTANT_NameAndType[12](name_index = 31, signature_index = 32)
31)CONSTANT_Utf8[1]("getResourceAsStream")
32)CONSTANT_Utf8[1]("(Ljava/lang/String;)Ljava/io/InputStream;")
33)CONSTANT_String[8](string_index = 34)
34)CONSTANT_Utf8[1]("DisplayDetails.class")
35)CONSTANT_Methodref[10](class_index = 23, name_and_type_index = 36)
36)CONSTANT_NameAndType[12](name_index = 7, signature_index = 37)
37)CONSTANT_Utf8[1]("(Ljava/io/InputStream;Ljava/lang/String;)V")
38)CONSTANT_Methodref[10](class_index = 23, name_and_type_index = 39)
39)CONSTANT_NameAndType[12](name_index = 40, signature_index = 41)
40)CONSTANT_Utf8[1]("parse")
41)CONSTANT_Utf8[1]("()Lorg/apache/bcel/classfile/JavaClass;")
42)CONSTANT_Fieldref[9](class_index = 43, name_and_type_index = 45)
43)CONSTANT_Class[7](name_index = 44)
44)CONSTANT_Utf8[1]("java/lang/System")
45)CONSTANT_NameAndType[12](name_index = 46, signature_index = 47)
46)CONSTANT_Utf8[1]("out")
47)CONSTANT_Utf8[1]("Ljava/io/PrintStream;")
48)CONSTANT_String[8](string_index = 49)
49)CONSTANT_Utf8[1]("*******Constant Pool*********")
50)CONSTANT_Methodref[10](class_index = 51, name_and_type_index = 53)
51)CONSTANT_Class[7](name_index = 52)
52)CONSTANT_Utf8[1]("java/io/PrintStream")
53)CONSTANT_NameAndType[12](name_index = 54, signature_index = 55)
54)CONSTANT_Utf8[1]("println")
55)CONSTANT_Utf8[1]("(Ljava/lang/String;)V")
56)CONSTANT_Methodref[10](class_index = 57, name_and_type_index = 59)
57)CONSTANT_Class[7](name_index = 58)
58)CONSTANT_Utf8[1]("org/apache/bcel/classfile/JavaClass")
59)CONSTANT_NameAndType[12](name_index = 60, signature_index = 61)
60)CONSTANT_Utf8[1]("getConstantPool")
61)CONSTANT_Utf8[1]("()Lorg/apache/bcel/classfile/ConstantPool;")
62)CONSTANT_Methodref[10](class_index = 51, name_and_type_index = 63)
63)CONSTANT_NameAndType[12](name_index = 54, signature_index = 64)
64)CONSTANT_Utf8[1]("(Ljava/lang/Object;)V")
65)CONSTANT_String[8](string_index = 66)
66)CONSTANT_Utf8[1]("*******Fields*********")
67)CONSTANT_Methodref[10](class_index = 57, name_and_type_index = 68)
68)CONSTANT_NameAndType[12](name_index = 69, signature_index = 70)
69)CONSTANT_Utf8[1]("getFields")
70)CONSTANT_Utf8[1]("()[Lorg/apache/bcel/classfile/Field;")
71)CONSTANT_Methodref[10](class_index = 72, name_and_type_index = 74)
72)CONSTANT_Class[7](name_index = 73)
73)CONSTANT_Utf8[1]("java/util/Arrays")
74)CONSTANT_NameAndType[12](name_index = 75, signature_index = 76)
75)CONSTANT_Utf8[1]("toString")
76)CONSTANT_Utf8[1]("([Ljava/lang/Object;)Ljava/lang/String;")
77)CONSTANT_Methodref[10](class_index = 51, name_and_type_index = 78)
78)CONSTANT_NameAndType[12](name_index = 54, signature_index = 8)
79)CONSTANT_String[8](string_index = 80)
80)CONSTANT_Utf8[1]("*******Methods*********")
81)CONSTANT_Methodref[10](class_index = 57, name_and_type_index = 82)
82)CONSTANT_NameAndType[12](name_index = 83, signature_index = 84)
83)CONSTANT_Utf8[1]("getMethods")
84)CONSTANT_Utf8[1]("()[Lorg/apache/bcel/classfile/Method;")
85)CONSTANT_Methodref[10](class_index = 86, name_and_type_index = 88)
86)CONSTANT_Class[7](name_index = 87)
87)CONSTANT_Utf8[1]("org/apache/bcel/classfile/Method")
88)CONSTANT_NameAndType[12](name_index = 89, signature_index = 90)
89)CONSTANT_Utf8[1]("getCode")
90)CONSTANT_Utf8[1]("()Lorg/apache/bcel/classfile/Code;")
91)CONSTANT_Utf8[1]("args")
92)CONSTANT_Utf8[1]("[Ljava/lang/String;")
93)CONSTANT_Utf8[1]("parser")
94)CONSTANT_Utf8[1]("Lorg/apache/bcel/classfile/ClassParser;")
95)CONSTANT_Utf8[1]("javaClass")
96)CONSTANT_Utf8[1]("Lorg/apache/bcel/classfile/JavaClass;")
97)CONSTANT_Utf8[1]("method")
98)CONSTANT_Utf8[1]("Lorg/apache/bcel/classfile/Method;")
99)CONSTANT_Utf8[1]("StackMapTable")
100)CONSTANT_Class[7](name_index = 92)
101)CONSTANT_Class[7](name_index = 102)
102)CONSTANT_Utf8[1]("[Lorg/apache/bcel/classfile/Method;")
103)CONSTANT_Utf8[1]("SourceFile")
104)CONSTANT_Utf8[1]("DisplayDetails.java")
*******Fields*********
[private static int sampleField]
*******Methods*********
[public void <init>(), public static void main(String[] args)
throws org.apache.bcel.classfile.ClassFormatException, java.io.IOException]
public void <init>()
Code(max_stack = 1, max_locals = 1, code_length = 5)
0: aload_0
1: invokespecial java.lang.Object.<init> ()V (10)
4: return
Attribute(s) =
LineNumber(0, 11)
LocalVariable(start_pc = 0, length = 5, index = 0:com.geekyarticles.bcel.DisplayDetails this)
public static void main(String[] args)
throws org.apache.bcel.classfile.ClassFormatException, java.io.IOException
Code(max_stack = 4, max_locals = 7, code_length = 138)
0: new <org.apache.bcel.classfile.ClassParser> (23)
3: dup
4: ldc com.geekyarticles.bcel.DisplayDetails (1)
6: ldc "/com/geekyarticles/bcel/DisplayDetails.class" (25)
8: invokevirtual java.lang.Class.getResourceAsStream (Ljava/lang/String;)Ljava/io/InputStream; (27)
11: ldc "DisplayDetails.class" (33)
13: invokespecial org.apache.bcel.classfile.ClassParser.<init> (Ljava/io/InputStream;Ljava/lang/String;)V (35)
16: astore_1
17: aload_1
18: invokevirtual org.apache.bcel.classfile.ClassParser.parse ()Lorg/apache/bcel/classfile/JavaClass; (38)
21: astore_2
22: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
25: ldc "*******Constant Pool*********" (48)
27: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (50)
30: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
33: aload_2
34: invokevirtual org.apache.bcel.classfile.JavaClass.getConstantPool ()Lorg/apache/bcel/classfile/ConstantPool; (56)
37: invokevirtual java.io.PrintStream.println (Ljava/lang/Object;)V (62)
40: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
43: ldc "*******Fields*********" (65)
45: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (50)
48: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
51: aload_2
52: invokevirtual org.apache.bcel.classfile.JavaClass.getFields ()[Lorg/apache/bcel/classfile/Field; (67)
55: invokestatic java.util.Arrays.toString ([Ljava/lang/Object;)Ljava/lang/String; (71)
58: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (50)
61: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
64: invokevirtual java.io.PrintStream.println ()V (77)
67: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
70: ldc "*******Methods*********" (79)
72: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (50)
75: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
78: aload_2
79: invokevirtual org.apache.bcel.classfile.JavaClass.getMethods ()[Lorg/apache/bcel/classfile/Method; (81)
82: invokestatic java.util.Arrays.toString ([Ljava/lang/Object;)Ljava/lang/String; (71)
85: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (50)
88: aload_2
89: invokevirtual org.apache.bcel.classfile.JavaClass.getMethods ()[Lorg/apache/bcel/classfile/Method; (81)
92: dup
93: astore %6
95: arraylength
96: istore %5
98: iconst_0
99: istore %4
101: goto #130
104: aload %6
106: iload %4
108: aaload
109: astore_3
110: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
113: aload_3
114: invokevirtual java.io.PrintStream.println (Ljava/lang/Object;)V (62)
117: getstatic java.lang.System.out Ljava/io/PrintStream; (42)
120: aload_3
121: invokevirtual org.apache.bcel.classfile.Method.getCode ()Lorg/apache/bcel/classfile/Code; (85)
124: invokevirtual java.io.PrintStream.println (Ljava/lang/Object;)V (62)
127: iinc %4 1
130: iload %4
132: iload %5
134: if_icmplt #104
137: return
Attribute(s) =
LineNumber(0, 21), LineNumber(17, 22), LineNumber(22, 24), LineNumber(30, 25),
LineNumber(40, 27), LineNumber(48, 28), LineNumber(61, 29), LineNumber(67, 31),
LineNumber(75, 32), LineNumber(88, 34), LineNumber(110, 35), LineNumber(117, 36),
LineNumber(127, 34), LineNumber(137, 38)
LocalVariable(start_pc = 0, length = 138, index = 0:String[] args)
LocalVariable(start_pc = 17, length = 121, index = 1:org.apache.bcel.classfile.ClassParser parser)
LocalVariable(start_pc = 22, length = 116, index = 2:org.apache.bcel.classfile.JavaClass javaClass)
LocalVariable(start_pc = 110, length = 17, index = 3:org.apache.bcel.classfile.Method method)
(Unknown attribute StackMapTable: 00 02 ff 00 68 00 07 07 00 64... (truncated))
Constant Pool Revisited: Let us now check the constant pool. There are many types of constants in the constant pool, some are class, some are string, some are UTF8 character sequence etc. Constants point one another for additional information. For example, a class constant points to a UTF8 character sequence for its name. For example, in this case, constant number 1 is a class constant which has a name reference to 2. Hence the name of the class is constant number 2 which is "com/geekyarticles/bcel/DisplayDetails". Note that the package separator here is '/'.
The field's description is pretty simple, no explanation needed. Note that the name of the field is actually present in constant pool at number 5. However, BCEL is differencing this location and showing the name in place.
Methods: As seen in the example, the class here has two methods. We know about the main method, but what is <init> ? It is the name of the construtor in the class file. The constructor's name in the class file is always this. Note that it is not a valid java identifier. This ensures that it is not possible to define a method in the class that conflicts with the constructor's name.
At the end, we have printed the code of each method. The code surely looks scary, but don't be paniced, you are not supposed to understand them yet. I will cover them slowly. At this stage, see that some attributes are also printed for each method's code. The attributes are line numbers, and local variable scope maps. We will deal with these attributes later.
In the class file structure, the code of the method is also just another attribute, but BCEL shows it separately.
JVM Code execution: Unlike most real machines, which are register based systems, JVM is a stack based system. What does it mean? Well for example, in an i386 processor, adding 2 and 3 would look something like (depending on the assembler, the terminologies may differ)
- mov ax 2
- mov bx 3
- add
- ldc 5
- ldc 7
- iadd
What we are trying to create: The following program shows what we are trying to create the byte code for. It means, when the following program compiles, it would create a byte code that would be very close to which we would create through BCEL.
package com.geekyarticles.bcel;
public class SyntheticClass {
public static void main(String[] args) {
System.out.println(" You are a real geek!");
}
}
public class SyntheticClass {
public static void main(String[] args) {
System.out.println(" You are a real geek!");
}
}
Yes, as simple as it could be. To do this, we must first get a reference to the static field out in the class java.lang.System. Then we need to call the method println on it passing the argument.
Getting reference to the out field is just one instruction.
- getstatic[constant number for field reference]
- ldc [constant number for the string argument]
- invokevirtual [constant number for method reference]
- return
Now that we understand the basics, we will accumulate these into code in GenerateClass.java
package com.geekyarticles.bcel;
import java.io.IOException;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.Type;
public class GenerateClass {
public static void main(String[] args) {
System.out.println("Generating Class");
//Create a ClassGen for our brand new class.
ClassGen classGen=new ClassGen("com.geekyarticles.bcel.SyntheticClass", "java.lang.Object", "SyntheticClass.java", Constants.ACC_PUBLIC, null);
//Get a reference to the constant pool of the class. This will be modified as we add methods, fields etc. Note that it already constains
//a few constants.
ConstantPoolGen constantPoolGen=classGen.getConstantPool();
//The list of instructions for a method.
InstructionList instructionList=new InstructionList();
//Add the appropriate instructions.
//Get the reference to static field out in class java.lang.System.
instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
//Load the constant
instructionList.append(new LDC(constantPoolGen.addString(" You are a real geek!")));
//Invoke the method.
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));
//Return from the method
instructionList.append(new RETURN());
MethodGen methodGen=new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_STATIC, Type.VOID, new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"}, "main", "com.geekyarticles.bcel.SyntheticClass", instructionList, constantPoolGen);
methodGen.setMaxLocals();//Calculate the maximum number of local variables.
methodGen.setMaxStack();//Very important: must calculate the maximum size of the stack.
classGen.addMethod(methodGen.getMethod()); //Add the method to the class
//Print a few things.
System.out.println("********Constant Pool**********");
System.out.println(constantPoolGen.getFinalConstantPool());
System.out.println("********Method**********");
System.out.println(methodGen);
System.out.println("********Instruction List**********");
System.out.println(instructionList);
//Now generate the class
JavaClass javaClass=classGen.getJavaClass();
try {
//Write the class byte code into a file
javaClass.dump("com/geekyarticles/bcel/SyntheticClass.class");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//That's it.
}
}
import java.io.IOException;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.Type;
public class GenerateClass {
public static void main(String[] args) {
System.out.println("Generating Class");
//Create a ClassGen for our brand new class.
ClassGen classGen=new ClassGen("com.geekyarticles.bcel.SyntheticClass", "java.lang.Object", "SyntheticClass.java", Constants.ACC_PUBLIC, null);
//Get a reference to the constant pool of the class. This will be modified as we add methods, fields etc. Note that it already constains
//a few constants.
ConstantPoolGen constantPoolGen=classGen.getConstantPool();
//The list of instructions for a method.
InstructionList instructionList=new InstructionList();
//Add the appropriate instructions.
//Get the reference to static field out in class java.lang.System.
instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
//Load the constant
instructionList.append(new LDC(constantPoolGen.addString(" You are a real geek!")));
//Invoke the method.
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));
//Return from the method
instructionList.append(new RETURN());
MethodGen methodGen=new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_STATIC, Type.VOID, new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"}, "main", "com.geekyarticles.bcel.SyntheticClass", instructionList, constantPoolGen);
methodGen.setMaxLocals();//Calculate the maximum number of local variables.
methodGen.setMaxStack();//Very important: must calculate the maximum size of the stack.
classGen.addMethod(methodGen.getMethod()); //Add the method to the class
//Print a few things.
System.out.println("********Constant Pool**********");
System.out.println(constantPoolGen.getFinalConstantPool());
System.out.println("********Method**********");
System.out.println(methodGen);
System.out.println("********Instruction List**********");
System.out.println(instructionList);
//Now generate the class
JavaClass javaClass=classGen.getJavaClass();
try {
//Write the class byte code into a file
javaClass.dump("com/geekyarticles/bcel/SyntheticClass.class");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//That's it.
}
}
Note here that we have added a constant in the constant pool whenever we have needed one. BCEL automatically ensures that the same constant is not added twice. The ConstantPool.add() method returns the index of the constant in the constant pool, which can be directly used in the instructions.
Descriptor: Java class files have very specific format for describing the type of a field or a method. During class file manipulation, whenever the type of a field or method needs to be provided, it needs to be in descriptor format.
Field Descriptor: Field descriptor is field's type. In class file, the signture is as follows:
Method Descriptor: Method descriptor is written in the form (parameterList)returnType. Hence, a method String myMethod(int x, Object [] y) has the descriptor (I[Ljava/lang/Object;)I. A void return type is represented by V.
Field Descriptor: Field descriptor is field's type. In class file, the signture is as follows:
Signature | Java Type |
---|---|
B | byte |
C | char |
D | double |
F | float |
I | int |
J | long |
S | short |
Z | boolean |
[ | array. Hence [B is a byte array, [Ljava/lang/Object; is an object array |
L<classname>; | object of class <classname>. The package name is slash separated. |
Method Descriptor: Method descriptor is written in the form (parameterList)returnType. Hence, a method String myMethod(int x, Object [] y) has the descriptor (I[Ljava/lang/Object;)I. A void return type is represented by V.
after running this programm, a class file should be generated. Now you should be able to do java com.geekyarticles.bcel.SyntheticClass and it should say You are a real geek!. Now that must be true, if the computer says so!
Here I will end the part one of this tutorial. More to come next.
1 comments:
Hey, very useful article. I have a question on when to do this, if I have to add new field in java class. is it during application build or application startup? I have web application developed using springs.
Post a Comment