blob: 8ffd37b4770aa07f055b11133ee9ce26af01f59a [file] [log] [blame]
/*
* 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);
}
}
}