更改已编译类中的所有类引用

时间:2016-05-24 18:03:04

标签: java javassist bcel

我正在尝试修改已编译的类(源代码不可用),例如,我想将对java.lang.Object的所有引用更改为some.packageName.SomeClass

我的意思是:

  • 字段类型
  • 方法返回类型
  • 方法参数类型
  • 超类型
  • 方法主体中的变量类型
  • 静态类引用(例如java.lang.Object.class
  • 通用类型参数

基本上,通过此示例,修改后的类不能直接访问java.lang.Object类,而只能通过some.packageName.SomeClass。请注意,示例类可以是jre中的任意类,也可以不是。提供的替代品的行为与原始预期完全相同。

这可以通过使用BCEL或Javassist来实现吗?如果没有,是否有其他库提供实现此目标的功能?

2 个答案:

答案 0 :(得分:1)

我还没有尝试过,但javassist和ASM当然可以在课堂上改变常量池。这是此类引用存储在类文件中的位置。

答案 1 :(得分:0)

我使用ASM,这非常容易。我有一个 org.objectweb.asm.commons.Remapper 的实现,它将类的名称和描述符更改为新的。

例如,其中一个方法如下所示:

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

描述如下: Lcom / example / Class; 。我提供给fixDesc的字段'重命名'是我创建的包含旧值到新值的类映射的映射。因此,如果我想将 com / example / AAA 转换为 com / example / BBB ,我将之前和之后的值提供给地图并像这样调用重映射:

/**
 * 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;
}