jboss-javassist / javassist

Java bytecode engineering toolkit
www.javassist.org
Other
4.1k stars 695 forks source link

Cannot change visibility of Nested classes #139

Closed paulo-raca closed 7 years ago

paulo-raca commented 7 years ago

I'm trying to make every class in a package public.

Basically, for every CtClass: ctClass.setModifiers( Modifier.setPublic(ctClass.getModifiers()));

This works fine for upper-level classes, but seems to have no effect on Subclasses.

(A few other manipulations work on subclasses just fine)

chibash commented 7 years ago

Did you call setModifiers on every subclass one by one? You have to do so.

paulo-raca commented 7 years ago

Yes. My code basically lists every .class file in the classpath, removes the .class suffix and replaces / with . to get a list of every class it needs to check. It will process each of these classes independently, ignoring whenever it's a subclass or not. It processes Outer and Outer$Inner, but the visibility is only updated on Outer.

I also apply some other changes using ctMethod.instrument(), and these work fine both for Outer and Inner classes.

paulo-raca commented 7 years ago

I've been investigating it a little, and I guess that since "outer" classes can only be public or package-visible, those are the only values mapped on CtClass.getModifiers().

If the class should by private, the resulting modifier actually says PUBLIC. If the class should by protected, the resulting modifier actually indicates "PACKAGE-VISIBLE".

I've also tested a few other modifiers (static, final, abstract) and these seem to work fine.

Here is a small gist with the code to reproduce it

paulo-raca commented 7 years ago

Another weird observation.

I'm now using ctClass.setModifiers( Modifier.setPublic(ctClass.getModifiers())); to update the classes.

Javassist and javap both see the modified classes as public.

AndroidStudio and the Fernflower decompiler do not, and show the unmodified visibility.

The only thing I can think of is that the access modifier is being stored in redundant places.

chibash commented 7 years ago

Ah, yes, you also have to update the InnerClasses attribute of the inner classes.

paulo-raca commented 7 years ago

How do I do that?

chibash commented 7 years ago

javassist.bytecode.InnerClassesAttribute#setAccessFlags

paulo-raca commented 7 years ago

Thank you!

Would it make sense to use InnerClassesAttribute automatically on CtClass.getModifiers() / CtClass.setModifiers() ?

chibash commented 7 years ago

I've modified CtClass.setModifiers() to do so.

paulo-raca commented 7 years ago

Thanks a lot!