Importing Classes
Classes are imported in ClassMaker
using these methods.
public void Import(Class javaClass) throws ClassMakerException public void Import(String className) throws ClassMakerException
Both methods make the class available using the short class name.
The method that takes a String
loads the class as well using the factory ClassLoader
.
The following code demonstrates how external classes can be imported either
using the class name or a reflection class.
Java code | ClassMaker code |
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public interface Openable { FileOutputStream open(File file) throws IOException; } public class OpenClass implements Openable { public FileOutputStream open(File file) throws IOException { FileOutputStream output; if (file.exists()) output = new FileOutputStream(file); else throw new IOException("File not found"); return output; } } |
maker.Import(File.class); maker.Import("java.io.FileOutputStream"); maker.Import("java.io.IOException"); maker.Implements(Openable.class); maker.Method("open", "FileOutputStream", ClassMaker.ACC_PUBLIC); maker.Declare("file", "File", 0); maker.Begin(); maker.Declare("output", "FileOutputStream", 0); maker.If(maker.Call(maker.Get("file"), "exists", null)); maker.Set("output", maker.New("FileOutputStream").Init(maker.Push(maker.Get("file")))); maker.Else(); maker.Throw(maker.New("IOException").Init(maker.Push(maker.Literal("File not found.")))); maker.EndIf(); maker.Return(maker.Get("output")); maker.End(); |
Extending a class
A generated class can extend another class using these methods.
public void Extends(String className) public void Extends(Class javaClass)
The first method takes either a fully qualified class name or a short class name if
the fully qualified class name has been previously imported.
The method loads the class as well using the factory ClassLoader
.
The second method takes a reflection class that represents a class type.
Creating a new instance
The following methods can be used to instantiate and initialise a class in ClassMaker
.
public Initialiser New(Class javaClass) throws ClassMakerException public Initialiser New(String className) throws ClassMakerException public class Initialiser { public ClassType Init(CallStack actualParameters) }
These methods are used in a sequence like this.
New( <class> ).Init( <call stack=""> )
The following code creates a new instance of !StringBuffer and calls the constructor that
takes an int
parameter.
maker.Implements(Create.class); maker.Method("create", StringBuffer.class, ACC_PUBLIC); maker.Begin(); maker.Return( maker.New(StringBuffer.class).Init(maker.Push(maker.Literal(150)))); maker.End();
The init
method must be called even if there are no parameters to the constructor;
otherwise the class will not be initialised.
Implementing an interface
The following methods can be used to implement an interface in ClassMaker
.
public void Implements(Class javaClass) throws ClassMakerException public void Implements(String className) throws ClassMakerException
The following code declares an interface called Unary
and then implements
the interface in a generated class.
public interface Unary { int square(int a); } public class SquareTestMaker extends ClassMakerBase { public void code() { Implements(Unary.class); Method("square", int.class, ACC_PUBLIC); Declare("a", int.class, 0); Begin(); Return(Mult(Get("a"), Get("a"))); End(); } } public void testSquareTest() throws Exception { ClassMaker maker = new SquareTestMaker(); Class squareClass = maker.defineClass(); Unary exec = (Unary)squareClass.newInstance(); assertEquals("Square test", 4, exec.square(2)); }
Implementing a generated interface
This code does something similar using a generated interface.
The interface is defined as "test.Unary"
.
It is then implemented by the class "test.SquareTest"
.
Finally, the class "test.UnaryTest"
calls the interface through a member field.
public void testGeneratedInterface() throws Exception { ClassMakerFactory factory = new ClassMakerFactory(); // Create interface test.Unary ClassMaker maker1 = factory.createClassMaker("test.Unary", Object.class, null); maker1.setIsInterface(); maker1.Method("square", int.class, ClassMaker.ACC_PUBLIC | ClassMaker.ACC_ABSTRACT); maker1.Declare("a", int.class, 0); maker1.Forward(); maker1.EndClass(); // Create a class that implements test.Unary ClassMaker maker2 = factory.createClassMaker("test.SquareTest", Object.class, null); maker2.Implements("test.Unary"); maker2.Method("square", int.class, ClassMaker.ACC_PUBLIC); maker2.Declare("a", int.class, 0); maker2.Begin(); maker2.Return(maker2.Mult(maker2.Get("a"), maker2.Get("a"))); maker2.End(); // Create a class that calls test.Unary ClassMaker maker3 = factory.createClassMaker("test.UnaryTest", Object.class, null); maker3.Implements(Unary.class); maker3.Declare("test", "test.Unary", ClassMaker.ACC_PUBLIC); maker3.Method("square", int.class, ClassMaker.ACC_PUBLIC); maker3.Declare("a", int.class, 0); maker3.Begin(); maker3.Return(maker3.Call(maker3.Get(maker3.This(), "test"), "square", maker3.Push(maker3.Get("a")))); maker3.End(); maker1.defineClass(); Class squareClass = maker2.defineClass(); Object squareTest = squareClass.newInstance(); Class testClass = maker3.defineClass(); Unary exec = (Unary)testClass.newInstance(); // Assign a reference to the interface to the member field exec.test using reflection. testClass.getField("test").set(exec, squareTest); assertEquals("Square test", 4, exec.square(2)); }