Ошибки при изменении существующего класса с использованием JavaAssist
Я работаю над следующей задачей CodeWars:
https://www.codewars.com/kata/hack-22/train/java
Вот что я написал:
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();
}
и я получаю следующую ошибку:
Исключение в потоке "main" javassist.CannotCompileException: by java.lang.ClassFormatError: класс SaneYossarian переопределяет последний метод isCrazy.()Z
Что не имеет смысла! Я использовал JavaAssist точно, чтобы изменить исходный класс. Я не ищу решения проблемы, просто понимаю, что я сделал неправильно на этапе, когда я изменил класс. Любая помощь приветствуется.
ОБНОВЛЕНИЕ: я также попытался напрямую изменить метод в базовом классе, чтобы вернуть true,
1 ответ
Вместо
final Class<?> aClass = saneYossarianClass.toClass(Yossarian.class.getClassLoader(), Yossarian.class.getProtectionDomain());
использование
final Class<?> aClass = saneYossarianClass.toClass();
По некоторым причинам это работает для меня:
public final class SomeClassHavingFinals {
public final void sayHelloBoy() {
System.out.println("I am saying hello original");
}
}
А также:
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);
}
выходы
Я переопределен
Похоже, это работает. Внутренние IDK, но кажется, что toClass() вызывает переопределение определения файла.