!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(); } }