javajavassistbcel

Change all class references in a compiled class


I am trying to modify a compiled class (source code is not available) which, for example, I want to change all references to java.lang.Object to some.packageName.SomeClass.

By references I mean:

Basically, by this example, the modified class should't be able to access the java.lang.Object class directly, but only through some.packageName.SomeClass. Please note that the example class may be any arbitrary class either from the jre or not. The supplied substitute will behave exactly as the original is expected.

Is this possible by using BCEL or Javassist? If not, is there any other library which provides functionality for accomplish this goal?


Solution

  • I use ASM and this is incredibly easy. I have an implementation of org.objectweb.asm.commons.Remapper that changes names and descriptors of classes to new ones.

    For example one of the methods looks like this:

    @Override
    public String mapDesc(String desc) {
        return super.mapDesc(StringUtil.fixDesc(desc, renamed));
    }
    

    A description looks like this: Lcom/example/Class;. The field 'renamed' that I feed into fixDesc is a map of class mappings that I've made that contain the old to new values. So if I want to make com/example/AAA into com/example/BBB I feed the before and after values into the map and call the remapper like so:

    /**
     * Given a map of ClassNodes and mappings, returns a map of class names to
     * class bytes.
     */
    public static Map<String, byte[]> process(Map<String, ClassNode> nodes, Map<String, MappedClass> mappings) {
        Map<String, byte[]> out = new HashMap<String, byte[]>();
        RemapperImpl mapper = new RemapperImpl(mappings);
        for (ClassNode cn : nodes.values()) {
            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
            ClassVisitor remapper = new ClassRemapper(cw, mapper);
            cn.accept(remapper);
            out.put(mappings.get(cn.name).getNewName(), cw.toByteArray());
        }
        return out;
    }