Ошибки при изменении существующего класса с использованием JavaAssist - PullRequest
0 голосов
/ 02 февраля 2019

Я работаю над следующей задачей 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: class SaneYossarian переопределяет конечный метод isCrazy. () Z

Что не имеет смысла!Я использовал JavaAssist точно, чтобы изменить исходный класс.Я не ищу решения проблемы, просто понимаю, что я сделал неправильно на этапе, когда я изменил класс.Любая помощь приветствуется.

ОБНОВЛЕНИЕ : Я также пытался напрямую изменить метод в базовом классе, чтобы получить значение true,

1 Ответ

0 голосов
/ 02 февраля 2019

Вместо

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 () вызывает переопределение определения файла.

...