| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| import java.io.IOException; |
| |
| import org.apache.bcel.Constants; |
| import org.apache.bcel.generic.ALOAD; |
| import org.apache.bcel.generic.ASTORE; |
| import org.apache.bcel.generic.ArrayType; |
| import org.apache.bcel.generic.ClassGen; |
| import org.apache.bcel.generic.ConstantPoolGen; |
| import org.apache.bcel.generic.GOTO; |
| import org.apache.bcel.generic.InstructionConstants; |
| import org.apache.bcel.generic.InstructionFactory; |
| import org.apache.bcel.generic.InstructionHandle; |
| import org.apache.bcel.generic.InstructionList; |
| import org.apache.bcel.generic.LocalVariableGen; |
| import org.apache.bcel.generic.MethodGen; |
| import org.apache.bcel.generic.ObjectType; |
| import org.apache.bcel.generic.PUSH; |
| import org.apache.bcel.generic.Type; |
| |
| /** |
| * Create HelloWorld class: |
| * <PRE> |
| * import java.io.*; |
| * |
| * public class HelloWorld { |
| * public static void main(String[] argv) { |
| * BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); |
| * String name = null; |
| * |
| * try { |
| * System.out.print("Please enter your name> "); |
| * name = in.readLine(); |
| * } catch(IOException e) { |
| * System.out.println(e); |
| * return; |
| * } |
| * |
| * System.out.println("Hello, " + name); |
| * } |
| * } |
| * </PRE> |
| * |
| * @version $Id$ |
| */ |
| public class HelloWorldBuilder { |
| public static void main(String[] argv) { |
| ClassGen cg = new ClassGen("HelloWorld", "java.lang.Object", |
| "<generated>", Constants.ACC_PUBLIC | |
| Constants.ACC_SUPER, |
| null); |
| ConstantPoolGen cp = cg.getConstantPool(); // cg creates constant pool |
| InstructionList il = new InstructionList(); |
| MethodGen mg = new MethodGen(Constants.ACC_STATIC | |
| Constants.ACC_PUBLIC,// access flags |
| Type.VOID, // return type |
| new Type[]{ // argument types |
| new ArrayType(Type.STRING, 1) |
| }, |
| new String[]{"argv"}, // arg names |
| "main", "HelloWorld", // method, class |
| il, cp); |
| InstructionFactory factory = new InstructionFactory(cg); |
| |
| ObjectType i_stream = new ObjectType("java.io.InputStream"); |
| ObjectType p_stream = new ObjectType("java.io.PrintStream"); |
| |
| // Create BufferedReader object and store it in local variable `in'. |
| il.append(factory.createNew("java.io.BufferedReader")); |
| il.append(InstructionConstants.DUP); // Use predefined constant, i.e. flyweight |
| il.append(factory.createNew("java.io.InputStreamReader")); |
| il.append(InstructionConstants.DUP); |
| il.append(factory.createFieldAccess("java.lang.System", "in", i_stream, Constants.GETSTATIC)); |
| |
| // Call constructors, i.e. BufferedReader(InputStreamReader()) |
| il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", |
| Type.VOID, new Type[]{i_stream}, |
| Constants.INVOKESPECIAL)); |
| il.append(factory.createInvoke("java.io.BufferedReader", "<init>", Type.VOID, |
| new Type[]{new ObjectType("java.io.Reader")}, |
| Constants.INVOKESPECIAL)); |
| |
| // Create local variable `in' |
| LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType("java.io.BufferedReader"), null, null); |
| int in = lg.getIndex(); |
| lg.setStart(il.append(new ASTORE(in))); // `i' valid from here |
| |
| // Create local variable `name' |
| lg = mg.addLocalVariable("name", Type.STRING, null, null); |
| int name = lg.getIndex(); |
| il.append(InstructionConstants.ACONST_NULL); |
| lg.setStart(il.append(new ASTORE(name))); // `name' valid from here |
| |
| // try { ... |
| InstructionHandle try_start = |
| il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC)); |
| |
| il.append(new PUSH(cp, "Please enter your name> ")); |
| il.append(factory.createInvoke("java.io.PrintStream", "print", Type.VOID, |
| new Type[]{Type.STRING}, Constants.INVOKEVIRTUAL)); |
| il.append(new ALOAD(in)); |
| il.append(factory.createInvoke("java.io.BufferedReader", "readLine", |
| Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); |
| il.append(new ASTORE(name)); |
| |
| // Upon normal execution we jump behind exception handler, the target address is not known yet. |
| GOTO g = new GOTO(null); |
| InstructionHandle try_end = il.append(g); |
| |
| /* } catch() { ... } |
| * Add exception handler: print exception and return from method |
| */ |
| InstructionHandle handler = |
| il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC)); |
| // Little trick in order not to save exception object temporarily |
| il.append(InstructionConstants.SWAP); |
| |
| il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[]{Type.OBJECT}, Constants.INVOKEVIRTUAL)); |
| il.append(InstructionConstants.RETURN); |
| mg.addExceptionHandler(try_start, try_end, handler, new ObjectType("java.io.IOException")); |
| |
| // Normal code continues, now we can set the branch target of the GOTO that jumps over the handler code. |
| InstructionHandle ih = |
| il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC)); |
| g.setTarget(ih); |
| |
| // String concatenation compiles to StringBuffer operations. |
| il.append(factory.createNew(Type.STRINGBUFFER)); |
| il.append(InstructionConstants.DUP); |
| il.append(new PUSH(cp, "Hello, ")); |
| il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", |
| Type.VOID, new Type[]{Type.STRING}, |
| Constants.INVOKESPECIAL)); |
| il.append(new ALOAD(name)); |
| |
| // Concatenate strings using a StringBuffer and print them. |
| il.append(factory.createInvoke("java.lang.StringBuffer", "append", |
| Type.STRINGBUFFER, new Type[]{Type.STRING}, |
| Constants.INVOKEVIRTUAL)); |
| il.append(factory.createInvoke("java.lang.StringBuffer", "toString", |
| Type.STRING, Type.NO_ARGS, |
| Constants.INVOKEVIRTUAL)); |
| |
| il.append(factory.createInvoke("java.io.PrintStream", "println", |
| Type.VOID, new Type[]{Type.STRING}, |
| Constants.INVOKEVIRTUAL)); |
| |
| il.append(InstructionConstants.RETURN); |
| |
| mg.setMaxStack(5); // Needed stack size |
| cg.addMethod(mg.getMethod()); |
| |
| il.dispose(); // Reuse instruction handles |
| |
| // Add public <init> method, i.e. empty constructor |
| cg.addEmptyConstructor(Constants.ACC_PUBLIC); |
| |
| // Get JavaClass object and dump it to file. |
| try { |
| cg.getJavaClass().dump("HelloWorld.class"); |
| } catch (IOException e) { |
| System.err.println(e); |
| } |
| } |
| } |