I'm new to javassist, and started to mess with it and got some things to work. However, there are also many other things that don't seem to work.
I made a method to inject code into classes-
public static void editMethodAddEvent(CtClass target, MethodInfo method, CtClass eventClass, int start, int[] bytes, int stacksize, String constructorParameters) throws BadBytecode, NotFoundException, CannotCompileException {
target.defrost();
CodeAttribute codeAttribute = method.getCodeAttribute();
CodeIterator iterator = codeAttribute.iterator();
int classID = method.getConstPool().addClassInfo(eventClass);
int constrnatID = method.getConstPool().addNameAndTypeInfo("<init>",constructorParameters);
int constructID = method.getConstPool().addMethodrefInfo(classID,constrnatID);
int callnatID = method.getConstPool().addNameAndTypeInfo("call","()V");
int callID = method.getConstPool().addMethodrefInfo(classID,callnatID);
iterator.insertGap(start,bytes.length);
for (int i = 0; i < bytes.length; i++) {
int byteCode = bytes[i];
if (byteCode >= 0) {
iterator.writeByte(byteCode, start+i);
} else if (byteCode == -1) {
iterator.writeByte(classID,start+i);
} else if (byteCode == -2) {
iterator.writeByte(constructID, start+i);
} else if (byteCode == -3) {
iterator.writeByte(callID, start+i);
}
}
if(stacksize > codeAttribute.getMaxStack())
codeAttribute.setMaxStack(stacksize);
target.toClass();
}
I use this code to add bytecode to a method, to fire an event when the code is run.
When I compile the class (target.toClass()) at the end, it does not error(and works fine).
However, when I add a method (empty constructor in this case), using the code below, it errors.
public static Class addEmptyConstructor(Class clazz) throws NotFoundException, CannotCompileException {
CtClass ctClass = ClassPool.getDefault().getCtClass(clazz.getName());
ctClass.defrost();
ClassFile classFile = ctClass.getClassFile();
MethodInfo newMethod = new MethodInfo(classFile.getConstPool(), "<init>", "()V");
newMethod.setCodeAttribute(new CodeAttribute(classFile.getConstPool(),1,1,new byte[]{0,0,0,0,0},new ExceptionTable(classFile.getConstPool())));
CodeIterator iterator = newMethod.getCodeAttribute().iterator();
iterator.writeByte(42, 0);
iterator.writeByte(183,1);
iterator.writeByte(0,2);
iterator.writeByte(1,3);
iterator.writeByte(177,4);
classFile.addMethod(newMethod);
return ClassPool.getDefault().toClass(ctClass);
}
The error given is:
javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "mod/TestClass"
at javassist.util.proxy.DefineClassHelper.toClass2(DefineClassHelper.java:140)
at javassist.util.proxy.DefineClassHelper.toClass(DefineClassHelper.java:95)
at javassist.ClassPool.toClass(ClassPool.java:1143)
at javassist.ClassPool.toClass(ClassPool.java:1106)
at javassist.ClassPool.toClass(ClassPool.java:1064)
at mod.edit.MethodEdit.addEmptyConstructor(MethodEdit.java:113)
<other nonrelevant stuff...>
Caused by: java.lang.LinkageError: loader (instance of
sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for
name: "haven/mod/TestClass"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at javassist.util.proxy.DefineClassHelper.toClass3(DefineClassHelper.java:152)
at javassist.util.proxy.DefineClassHelper.toClass2(DefineClassHelper.java:134)
... 10 more
My goal is to create an empty constructor so that I can create an instance of any object without putting in parameters. Specifically I have a lot of kinds of events, that have parameters. I don't want to be able to access this constructor at compile time. Thus, I try to add a constructor with javassist during runtime, and it refuses to compile. If I simply edit a method, it does not fuss, but if I add a method, it seems to refuse to do what I want. How do I solve this problem? I've been trying for over 16 hours, researching, testing different code, and can't get anything to work. Please Help!!!!