1 Reply Latest reply on Jul 16, 2008 7:00 AM by drag0p

    Removing final modifier of inner classes

    mburger

      Hello!

      I've written a tool that removes the final modifier from class files. That works perfectly with "outer" classes, but with inner classes javassist seems to fail. Here is a small test case.

      The class FinalRemover does the job:

      package test;
      
      import javassist.ClassPool;
      import javassist.CtClass;
      import javassist.Modifier;
      
      public class FinalRemover {
      
       public static void main(String[] args) throws Exception {
       process("test.NoInner");
       process("test.WithInner");
       process("test.WithInner$NotStatic");
       process("test.WithInner$Static");
       }
      
       public static void process(String className) throws Exception {
       System.out.println("Processing class: " + className);
       ClassPool pool = ClassPool.getDefault();
      
       CtClass cc = pool.get(className);
       removeFinal(cc);
      
       if (Modifier.isFinal(cc.getModifiers())) {
       throw new IllegalStateException("Class '" + className + "' is not final?!?");
       }
      
       cc.writeFile("/tmp/test_patched/patched");
       System.out.println("Class was written: " + className);
       System.out.println();
       }
      
       protected static void removeFinal(CtClass clazz) {
      
       int modifiers = clazz.getModifiers();
      
       if (Modifier.isFinal(modifiers)) {
       System.out.println("Removing final modifier: " + clazz.getName());
       int notFinalModifier = Modifier.clear(modifiers, Modifier.FINAL);
       clazz.setModifiers(notFinalModifier);
       }
      
       }
      
      }
      


      The class NoInner has no inner class:

      package test;
      
      public final class NoInner {
      
      }
      


      Finally, the class WithInner has two inner classes:

      package test;
      
      public class WithInner {
      
       public WithInner() {
       super();
       }
      
       public static final class Static {
      
       public static final String CONST = "Static inner class";
      
       }
      
       public final class NotStatic {
      
       public static final String CONST = "Not static inner class";
      
       }
      
      }
      


      Running the tool writes the following output:

      Processing class: test.NoInner
      Removing final modifier: test.NoInner
      Class was written: test.NoInner
      
      Processing class: test.WithInner
      Class was written: test.WithInner
      
      Processing class: test.WithInner$NotStatic
      Removing final modifier: test.WithInner$NotStatic
      Class was written: test.WithInner$NotStatic
      
      Processing class: test.WithInner$Static
      Removing final modifier: test.WithInner$Static
      Class was written: test.WithInner$Static
      


      I decompiled the written class files using JAD. A diff between the original and the patched class NoInner shows the expected result:

      $ diff orig/NoInner.jad patched/NoInner.jad
      9c9
      < public final class NoInner
      ---
      > public class NoInner
      


      But, between the original and the patched class WithInner, there is no difference:

      $ diff orig/WithInner.jad patched/WithInner.jad
      


      Thus, the final modifier was not removed from the byte code. Please note the IllegalStateException in my code: javassist thinks that modifier was removed, but it is still contained in the byte code written the the file.

      Any ideas?

      Regards

      Martin