This repository has been archived by the owner on Aug 10, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
Example
Brian S. O'Neill edited this page Feb 7, 2021
·
5 revisions
An example class is provided (cojen.example.HelloWorld) which demonstrates dynamic class generation and loading. It creates a class equivalent to the following, loads it, and then invokes the main method. Based on HelloWorldBuilder from the Apache BCEL project.
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) { return; } System.out.println("Hello, " + name); } }
Here is the full source to the example, sans header comments for brevity:
package org.cojen.example; // Used to generate the class import org.cojen.classfile.CodeBuilder; import org.cojen.classfile.Label; import org.cojen.classfile.LocalVariable; import org.cojen.classfile.MethodInfo; import org.cojen.classfile.Modifiers; import org.cojen.classfile.RuntimeClassFile; import org.cojen.classfile.TypeDesc; // Used to execute the generated class import java.lang.reflect.Method; public class HelloWorld { public static void main(String[] args) throws Exception { // Create the RuntimeClassFile using an automatically selected name. RuntimeClassFile cf = createClassFile(); Class clazz = cf.defineClass(); // Find the generated main method and invoke it. Method m = clazz.getMethod("main", new Class[] {String[].class}); m.invoke(null, new Object[] {args}); } /** * Creates a ClassFile which defines a simple interactive HelloWorld class. * * @param className name given to class */ private static RuntimeClassFile createClassFile() { // Create a ClassFile with the super class of Object. RuntimeClassFile cf = new RuntimeClassFile(); // Default constructor works only if super class has an accessible // no-arg constructor. cf.addDefaultConstructor(); // Add the main method, and construct a CodeBuilder for defining the // bytecode. TypeDesc[] params = new TypeDesc[] {TypeDesc.STRING.toArrayType()}; MethodInfo mi = cf.addMethod(Modifiers.PUBLIC_STATIC, "main", null, params); CodeBuilder b = new CodeBuilder(mi); // Create some types which will be needed later. TypeDesc bufferedReader = TypeDesc.forClass("java.io.BufferedReader"); TypeDesc inputStreamReader = TypeDesc.forClass("java.io.InputStreamReader"); TypeDesc inputStream = TypeDesc.forClass("java.io.InputStream"); TypeDesc reader = TypeDesc.forClass("java.io.Reader"); TypeDesc stringBuffer = TypeDesc.forClass("java.lang.StringBuffer"); TypeDesc printStream = TypeDesc.forClass("java.io.PrintStream"); // Declare local variables to be used. LocalVariable in = b.createLocalVariable("in", bufferedReader); LocalVariable name = b.createLocalVariable("name", TypeDesc.STRING); // Create the first line of code, corresponding to // in = new BufferedReader(new InputStreamReader(System.in)); b.newObject(bufferedReader); b.dup(); b.newObject(inputStreamReader); b.dup(); b.loadStaticField("java.lang.System", "in", inputStream); params = new TypeDesc[] {inputStream}; b.invokeConstructor(inputStreamReader.getRootName(), params); params = new TypeDesc[] {reader}; b.invokeConstructor(bufferedReader.getRootName(), params); b.storeLocal(in); // Create and locate a label for the start of the "try" block. Label tryStart = b.createLabel().setLocation(); // Create input prompt. b.loadStaticField("java.lang.System", "out", printStream); b.loadConstant("Please enter your name> "); params = new TypeDesc[] {TypeDesc.STRING}; b.invokeVirtual(printStream, "print", null, params); // Read a line from the reader, and store it in the "name" variable. b.loadLocal(in); b.invokeVirtual(bufferedReader, "readLine", TypeDesc.STRING, null); b.storeLocal(name); // If no exception is thrown, branch to a label to print the // response. The location of the label has not yet been set. Label printResponse = b.createLabel(); b.branch(printResponse); // Create and locate a label for the end of the "try" block. Label tryEnd = b.createLabel().setLocation(); // Create the "catch" block. b.exceptionHandler(tryStart, tryEnd, "java.io.IOException"); b.returnVoid(); // If no exception, then branch to this location to print the response. printResponse.setLocation(); // Create the line of code, corresponding to // System.out.println("Hello, " + name); b.loadStaticField("java.lang.System", "out", printStream); b.newObject(stringBuffer); b.dup(); b.loadConstant("Hello, "); params = new TypeDesc[] {TypeDesc.STRING}; b.invokeConstructor(stringBuffer, params); b.loadLocal(name); b.invokeVirtual(stringBuffer, "append", stringBuffer, params); b.invokeVirtual(stringBuffer, "toString", TypeDesc.STRING, null); params = new TypeDesc[] {TypeDesc.STRING}; b.invokeVirtual(printStream, "println", null, params); // The last instruction reached must be a return or else the class // verifier will complain. b.returnVoid(); return cf; } }