1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 import java.io.IOException; 20 21 import org.apache.bcel.Constants; 22 import org.apache.bcel.generic.ALOAD; 23 import org.apache.bcel.generic.ASTORE; 24 import org.apache.bcel.generic.ArrayType; 25 import org.apache.bcel.generic.ClassGen; 26 import org.apache.bcel.generic.ConstantPoolGen; 27 import org.apache.bcel.generic.GOTO; 28 import org.apache.bcel.generic.InstructionConstants; 29 import org.apache.bcel.generic.InstructionFactory; 30 import org.apache.bcel.generic.InstructionHandle; 31 import org.apache.bcel.generic.InstructionList; 32 import org.apache.bcel.generic.LocalVariableGen; 33 import org.apache.bcel.generic.MethodGen; 34 import org.apache.bcel.generic.ObjectType; 35 import org.apache.bcel.generic.PUSH; 36 import org.apache.bcel.generic.Type; 37 38 /** 39 * Create HelloWorld class: 40 * <PRE> 41 * import java.io.*; 42 * 43 * public class HelloWorld { 44 * public static void main(String[] argv) { 45 * BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 46 * String name = null; 47 * 48 * try { 49 * System.out.print("Please enter your name> "); 50 * name = in.readLine(); 51 * } catch(IOException e) { 52 * System.out.println(e); 53 * return; 54 * } 55 * 56 * System.out.println("Hello, " + name); 57 * } 58 * } 59 * </PRE> 60 * 61 * @version $Id$ 62 */ 63 public class HelloWorldBuilder { main(String[] argv)64 public static void main(String[] argv) { 65 ClassGen cg = new ClassGen("HelloWorld", "java.lang.Object", 66 "<generated>", Constants.ACC_PUBLIC | 67 Constants.ACC_SUPER, 68 null); 69 ConstantPoolGen cp = cg.getConstantPool(); // cg creates constant pool 70 InstructionList il = new InstructionList(); 71 MethodGen mg = new MethodGen(Constants.ACC_STATIC | 72 Constants.ACC_PUBLIC,// access flags 73 Type.VOID, // return type 74 new Type[]{ // argument types 75 new ArrayType(Type.STRING, 1) 76 }, 77 new String[]{"argv"}, // arg names 78 "main", "HelloWorld", // method, class 79 il, cp); 80 InstructionFactory factory = new InstructionFactory(cg); 81 82 ObjectType i_stream = new ObjectType("java.io.InputStream"); 83 ObjectType p_stream = new ObjectType("java.io.PrintStream"); 84 85 // Create BufferedReader object and store it in local variable `in'. 86 il.append(factory.createNew("java.io.BufferedReader")); 87 il.append(InstructionConstants.DUP); // Use predefined constant, i.e. flyweight 88 il.append(factory.createNew("java.io.InputStreamReader")); 89 il.append(InstructionConstants.DUP); 90 il.append(factory.createFieldAccess("java.lang.System", "in", i_stream, Constants.GETSTATIC)); 91 92 // Call constructors, i.e. BufferedReader(InputStreamReader()) 93 il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", 94 Type.VOID, new Type[]{i_stream}, 95 Constants.INVOKESPECIAL)); 96 il.append(factory.createInvoke("java.io.BufferedReader", "<init>", Type.VOID, 97 new Type[]{new ObjectType("java.io.Reader")}, 98 Constants.INVOKESPECIAL)); 99 100 // Create local variable `in' 101 LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType("java.io.BufferedReader"), null, null); 102 int in = lg.getIndex(); 103 lg.setStart(il.append(new ASTORE(in))); // `i' valid from here 104 105 // Create local variable `name' 106 lg = mg.addLocalVariable("name", Type.STRING, null, null); 107 int name = lg.getIndex(); 108 il.append(InstructionConstants.ACONST_NULL); 109 lg.setStart(il.append(new ASTORE(name))); // `name' valid from here 110 111 // try { ... 112 InstructionHandle try_start = 113 il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC)); 114 115 il.append(new PUSH(cp, "Please enter your name> ")); 116 il.append(factory.createInvoke("java.io.PrintStream", "print", Type.VOID, 117 new Type[]{Type.STRING}, Constants.INVOKEVIRTUAL)); 118 il.append(new ALOAD(in)); 119 il.append(factory.createInvoke("java.io.BufferedReader", "readLine", 120 Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 121 il.append(new ASTORE(name)); 122 123 // Upon normal execution we jump behind exception handler, the target address is not known yet. 124 GOTO g = new GOTO(null); 125 InstructionHandle try_end = il.append(g); 126 127 /* } catch() { ... } 128 * Add exception handler: print exception and return from method 129 */ 130 InstructionHandle handler = 131 il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC)); 132 // Little trick in order not to save exception object temporarily 133 il.append(InstructionConstants.SWAP); 134 135 il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[]{Type.OBJECT}, Constants.INVOKEVIRTUAL)); 136 il.append(InstructionConstants.RETURN); 137 mg.addExceptionHandler(try_start, try_end, handler, new ObjectType("java.io.IOException")); 138 139 // Normal code continues, now we can set the branch target of the GOTO that jumps over the handler code. 140 InstructionHandle ih = 141 il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC)); 142 g.setTarget(ih); 143 144 // String concatenation compiles to StringBuffer operations. 145 il.append(factory.createNew(Type.STRINGBUFFER)); 146 il.append(InstructionConstants.DUP); 147 il.append(new PUSH(cp, "Hello, ")); 148 il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", 149 Type.VOID, new Type[]{Type.STRING}, 150 Constants.INVOKESPECIAL)); 151 il.append(new ALOAD(name)); 152 153 // Concatenate strings using a StringBuffer and print them. 154 il.append(factory.createInvoke("java.lang.StringBuffer", "append", 155 Type.STRINGBUFFER, new Type[]{Type.STRING}, 156 Constants.INVOKEVIRTUAL)); 157 il.append(factory.createInvoke("java.lang.StringBuffer", "toString", 158 Type.STRING, Type.NO_ARGS, 159 Constants.INVOKEVIRTUAL)); 160 161 il.append(factory.createInvoke("java.io.PrintStream", "println", 162 Type.VOID, new Type[]{Type.STRING}, 163 Constants.INVOKEVIRTUAL)); 164 165 il.append(InstructionConstants.RETURN); 166 167 mg.setMaxStack(5); // Needed stack size 168 cg.addMethod(mg.getMethod()); 169 170 il.dispose(); // Reuse instruction handles 171 172 // Add public <init> method, i.e. empty constructor 173 cg.addEmptyConstructor(Constants.ACC_PUBLIC); 174 175 // Get JavaClass object and dump it to file. 176 try { 177 cg.getJavaClass().dump("HelloWorld.class"); 178 } catch (IOException e) { 179 System.err.println(e); 180 } 181 } 182 } 183