使用bcel动态创建class
Apache的BCEL库,文档很少,例子也很简单。动态构建类的工作,要求的只是并不是熟练使用BCEL类库本身,而是要对java的class结构了解。我对java的pcode也不熟悉,但是我曾经做过大量的.NET的反编译工作,两者类似,所以我用BCEL也不觉得困难。
我提供一个例子,这里例子是使用BCEL创建类的实例,而不是使用反射。
如下:
IFactory.java
public interface IFactory {
public Object newInstance();
}
public Object newInstance();
}
FileClassLoader.java
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class FileClassLoader extends ClassLoader {
public FileClassLoader() {
super();
}
public FileClassLoader(ClassLoader parent) {
super(parent);
}
public Class getClass(String className, String filePath) {
FileInputStream fileInputStream = null;
byte[] data = null;
try {
fileInputStream = new FileInputStream(new File(filePath));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int ch = 0;
while ((ch = fileInputStream.read()) != -1) {
byteArrayOutputStream.write(ch);
}
data = byteArrayOutputStream.toByteArray();
return defineClass(className, data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
throw new Error(e.getMessage(), e);
}
}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class FileClassLoader extends ClassLoader {
public FileClassLoader() {
super();
}
public FileClassLoader(ClassLoader parent) {
super(parent);
}
public Class getClass(String className, String filePath) {
FileInputStream fileInputStream = null;
byte[] data = null;
try {
fileInputStream = new FileInputStream(new File(filePath));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int ch = 0;
while ((ch = fileInputStream.read()) != -1) {
byteArrayOutputStream.write(ch);
}
data = byteArrayOutputStream.toByteArray();
return defineClass(className, data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
throw new Error(e.getMessage(), e);
}
}
}
buildFactory方法:
public static IFactory buildFactory(String procductClassName)
throws Exception {
InstructionList il = new InstructionList();
String className = "HelloWorld";
ClassGen class_gen = new ClassGen(className, "java.lang.Object",
" ", Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);
ConstantPoolGen cons_pool = class_gen.getConstantPool();
class_gen.addInterface(IFactory.class.getName());
InstructionFactory il_factory = new InstructionFactory(class_gen);
// 创建构造函数
{
String methodName = " ";
Type returnType = Type.VOID;
Type[] arg_Types = new Type[] {};
String[] arg_names = new String[] {};
MethodGen method_gen = new MethodGen(Constants.ACC_PUBLIC,
returnType, arg_Types, arg_names, methodName, className,
il, cons_pool);
// super();
il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
il.append(il_factory.createInvoke("java.lang.Object", " ",
Type.VOID, new Type[0], Constants.INVOKESPECIAL));
il.append(InstructionFactory.createReturn(Type.VOID));
method_gen.setMaxStack();
class_gen.addMethod(method_gen.getMethod());
il.dispose(); // Reuse instruction handles of list
}
{
String methodName = "newInstance";
Type returnType = Type.OBJECT;
Type[] arg_Types = new Type[] {};
String[] arg_names = new String[] {};
MethodGen method_gen = new MethodGen(Constants.ACC_PUBLIC,
returnType, arg_Types, arg_names, methodName, className,
il, cons_pool);
il.append(il_factory.createNew(procductClassName));
il.append(InstructionConstants.DUP);
il.append(il_factory.createInvoke(procductClassName, " ",
Type.VOID, new Type[0], Constants.INVOKESPECIAL));
il.append(InstructionFactory.createReturn(Type.OBJECT));
method_gen.setMaxStack();
class_gen.addMethod(method_gen.getMethod());
il.dispose(); // Reuse instruction handles of list
}
// 保存到文件中
JavaClass clazz = class_gen.getJavaClass();
String path = "e:\\temp\\" + className + ".class";
class_gen.getJavaClass().dump(path);
// 使用ClassLoader装载class
FileClassLoader classLoader = new FileClassLoader();
Class factoryClass = classLoader.getClass(className, path);
Object newInst = factoryClass.newInstance();
return (IFactory) newInst;
}
throws Exception {
InstructionList il = new InstructionList();
String className = "HelloWorld";
ClassGen class_gen = new ClassGen(className, "java.lang.Object",
"
ConstantPoolGen cons_pool = class_gen.getConstantPool();
class_gen.addInterface(IFactory.class.getName());
InstructionFactory il_factory = new InstructionFactory(class_gen);
// 创建构造函数
{
String methodName = "
Type returnType = Type.VOID;
Type[] arg_Types = new Type[] {};
String[] arg_names = new String[] {};
MethodGen method_gen = new MethodGen(Constants.ACC_PUBLIC,
returnType, arg_Types, arg_names, methodName, className,
il, cons_pool);
// super();
il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
il.append(il_factory.createInvoke("java.lang.Object", "
Type.VOID, new Type[0], Constants.INVOKESPECIAL));
il.append(InstructionFactory.createReturn(Type.VOID));
method_gen.setMaxStack();
class_gen.addMethod(method_gen.getMethod());
il.dispose(); // Reuse instruction handles of list
}
{
String methodName = "newInstance";
Type returnType = Type.OBJECT;
Type[] arg_Types = new Type[] {};
String[] arg_names = new String[] {};
MethodGen method_gen = new MethodGen(Constants.ACC_PUBLIC,
returnType, arg_Types, arg_names, methodName, className,
il, cons_pool);
il.append(il_factory.createNew(procductClassName));
il.append(InstructionConstants.DUP);
il.append(il_factory.createInvoke(procductClassName, "
Type.VOID, new Type[0], Constants.INVOKESPECIAL));
il.append(InstructionFactory.createReturn(Type.OBJECT));
method_gen.setMaxStack();
class_gen.addMethod(method_gen.getMethod());
il.dispose(); // Reuse instruction handles of list
}
// 保存到文件中
JavaClass clazz = class_gen.getJavaClass();
String path = "e:\\temp\\" + className + ".class";
class_gen.getJavaClass().dump(path);
// 使用ClassLoader装载class
FileClassLoader classLoader = new FileClassLoader();
Class factoryClass = classLoader.getClass(className, path);
Object newInst = factoryClass.newInstance();
return (IFactory) newInst;
}
测试用例:
String className = "java.lang.Object";
IFactory factory = buildFactory(className);
Object inst = factory.newInstance();
IFactory factory = buildFactory(className);
Object inst = factory.newInstance();