!include once #1019934 // BCEL
// A = interface we are implementing
sclass ClassMaker {
gettable S className;
gettable ClassGen cg;
JavaClass baked;
InMemoryClassLoader classLoader;
Class loadedClass;
settable bool printDisassembly;
settable S superClassName = "java.lang.Object";
settable S fileName;
*(S className) {
this(className, null);
}
*(S *className, S *superClassName, S[] interfaces) {
setClassGen(new ClassGen(className, superClassName, fileName,
Const.ACC_PUBLIC, interfaces));
}
*(S *className, S[] interfaces) {
setClassGen(new ClassGen(className, superClassName, fileName,
Const.ACC_PUBLIC, interfaces));
}
*(Class interfaceToImplement) {
className = randomClassName();
setClassGen(new ClassGen(className, "java.lang.Object", null,
Const.ACC_PUBLIC, new S[] { main className(interfaceToImplement) }));
addDefaultConstructor();
}
void addDefaultConstructor {
cg.addEmptyConstructor(Const.ACC_PUBLIC);
}
void setClassGen(ClassGen cg) {
this.cg = cg;
// up the byte code version so we can do ldc of class objects (e.g.)
cg.setMajor(50); // JDK 6
//cg.setMajor(55); // JDK 11. can't use yet because StackMapTable became mandatory in JDK 8 and BCEL doesn't generate that
cg.setMinor(0);
}
JavaClass bake() {
if (baked == null) {
baked = cg.getJavaClass();
if (printDisassembly)
printClassWithMethods();
}
ret baked;
}
// tabs can look bad in JTextArea, so we're using tabToSingleSpace
void printClassWithMethods() {
// print class overview
print_tabToSingleSpace(bake());
// print the methods
for (method : baked.getMethods()) {
print_tabToSingleSpace("\n" + method);
print_tabToSingleSpace(method.getCode());
}
}
simplyCached byte[] toBytes aka getBytes() {
ret bake().getBytes();
}
Class load() {
if (loadedClass == null) {
var bytes = toBytes();
classLoader = new InMemoryClassLoader(myClassLoader());
loadedClass = (Class) classLoader.defineAClass(className, bytes);
}
ret loadedClass;
}
A newInstance() {
ret main newInstance(load());
}
void addField(FieldGen fg) {
cg.addField(fg.getField());
}
ConstantPoolGen getConstantPool() {
ret cg.getConstantPool();
}
}