我正在尝试修改已编译的类(源代码不可用),例如,我想将对java.lang.Object
的所有引用更改为some.packageName.SomeClass
。
我的意思是:
java.lang.Object.class
)基本上,通过此示例,修改后的类不能直接访问java.lang.Object
类,而只能通过some.packageName.SomeClass
。请注意,示例类可以是jre中的任意类,也可以不是。提供的替代品的行为与原始预期完全相同。
这可以通过使用BCEL或Javassist来实现吗?如果没有,是否有其他库提供实现此目标的功能?
答案 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;
}