Errors Modifying an Existing Class Using Javaassist
I'm Working on the Following Codewars Challenge: Here's What I've Written: Public Static Yossarian Loophole() Throws Throwable { Classpool Pool = Classpool...
I'm working on the following CodeWars challenge :
Here's what I've written :
public static Yossarian loophole() throws Throwable {
ClassPool pool = ClassPool.getDefault();
//Loader cl = new Loader(pool);
CtClass yossarianClass = pool.get("Yossarian");
int modifiers = yossarianClass.getDeclaredMethod("isCrazy").getModifiers();
if(Modifier.isFinal(modifiers)) {
System.out.println("Removing Final");
int notFinalModifier = Modifier.clear(modifiers, Modifier.FINAL);
yossarianClass.getDeclaredMethod("isCrazy").setModifiers(notFinalModifier);
yossarianClass.rebuildClassFile();
}
final CtClass saneYossarianClass = ClassPool.getDefault().makeClass("SaneYossarian");
saneYossarianClass.setSuperclass(yossarianClass);
final CtMethod overrideMethod = CtNewMethod.make("public boolean isCrazy() { return true; }", saneYossarianClass);
saneYossarianClass.addMethod(overrideMethod);
final Class<?> aClass = saneYossarianClass.toClass(Yossarian.class.getClassLoader(), Yossarian.class.getProtectionDomain());
return (Yossarian) aClass.newInstance();
}
and I get the following error :
Exception in thread "main" javassist.CannotCompileException: by java.lang.ClassFormatError: class SaneYossarian overrides final method isCrazy.()Z
Which makes no sense! I used JavaAssist precisely to modify the original class. I'm not looking for a solution to the challenge, just an understanding of what I did wrong in the step where I modified the class. Any help is appreciated.
UPDATE : I also tried directly modifying the method in the base class to return true,
1 Answer
Instead of
final Class<?> aClass = saneYossarianClass.toClass(Yossarian.class.getClassLoader(), Yossarian.class.getProtectionDomain());
use
final Class<?> aClass = saneYossarianClass.toClass();
For some reasons this works for me:
public final class SomeClassHavingFinals {
public final void sayHelloBoy() {
System.out.println("I am saying hello original");
}
}
And:
public static void main(String[] args)
throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException,
NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, IOException {
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.get("testapp.SomeClassHavingFinals");
clazz.defrost();
clazz.setModifiers(Modifier.PUBLIC);
clazz.getDeclaredMethod("sayHelloBoy").setModifiers(Modifier.PUBLIC);
clazz.toClass();
CtClass extension = pool.makeClass("SomeExtension");
extension.setSuperclass(clazz);
final CtMethod overrideMethod = CtNewMethod.make("public void sayHelloBoy() { System.out.println(\"Im overriden\"); }",
extension);
extension.addMethod(overrideMethod);
Object ei = extension.toClass().newInstance();
ei.getClass().getDeclaredMethod("sayHelloBoy").invoke(ei);
}
outputs
Im overriden
so it looks like it is working. IDK internals, but it seems that toClass() causes the file definition to be rebuilt.