我有以下代码:
for (Map.Entry<String, ClassReader> e : classes.entrySet())
{
ClassReader reader = e.getValue();
ClassWriter writer = new ClassWriter(Opcodes.ASM7);
// Process all visitors
reader.accept(new StringRemapper(writer, "String A", "String A!!"), ClassReader.EXPAND_FRAMES);
reader.accept(new StringRemapper(writer, "String B", "String B!!"), ClassReader.EXPAND_FRAMES);
// Update the class
reader = new ClassReader(writer.toByteArray());
e.setValue(reader);
}
上面的代码的问题在于,它会将所有内容写两次,因为有两个访问者正在向同一位作者写信(我想)。
要解决此问题,我需要在每个reader.accept
之后添加以下代码:
reader = new ClassReader(writer.toByteArray());
writer = new ClassWriter(Opcodes.ASM7);
这样做是在滥用访客模式吗?我的意思是,为什么我需要创建一个新的读者/作家并仅访问一次?我不应该可以有多个访客吗?
我发现了类似的问题Easy way to stack up a couple of ASM-Bytecode visitors?,但无法理解接受的答案。
我试图将第一个访问者作为参数传递给第二个访问者,而不是原始的ClassWriter,其结果相同,代码重复。
ClassVisitor last;
// Process all visitors
reader.accept(last = new StringRemapper(writer, "String A", "String A!!"), ClassReader.EXPAND_FRAMES);
reader.accept(new StringRemapper(last, "String B", "String B!!"), ClassReader.EXPAND_FRAMES);
您是对的,您确实错过了一些事情:ClassWriter
本身就是ClassVisitor
。
堆叠访问者的正确方法是将其父访问者传递给构造函数:
// The root visitor is the ClassWriter
ClassVisitor cv = writer;
// Add a visitor
cv = new StringRemapper(cv, "String A", "String A!!");
// Add an other
cv = new StringRemapper(cv, "String B", "String B!!");
// maybe add more?
// process them
reader.accept(cv, ClassReader.EXPAND_FRAMES);
byte[] classFile = writer.toByteArray();
如果StringRemapper
仅采用ClassWriter
作为参数,则应更改它以接受ClassVisitor
的读入。
[我注意到的另一件事是您的classes
变量:它包含ClassReader
作为值。将ClassVisitors
用作值-具有初始ClassWriter
值可能更容易设计。但这是一个更大的设计更改。