代码之家  ›  专栏  ›  技术社区  ›  Amir Afghani

使用JavaAssist修改现有类时出错

  •  1
  • Amir Afghani  · 技术社区  · 6 年前

    我正在进行以下代码战挑战:

    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:由java编写。ClassFormatError:类SaneYossarian覆盖最终方法isCrazy。()Z

    使现代化

    1 回复  |  直到 6 年前
        1
  •  1
  •   Antoniossss    6 年前

    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()似乎会导致重新生成文件定义。