Putting it together
- Java course
- Expert
- Lesson 41/46
- 6 min
Combine all parts to write a bytecode inspector.
Project: combine
In the final lesson you will combine all pieces and complete the visitor chain. A void visitEnd(); method is added to ClassVisitor; it is called at the end of the traversal. ClassReader.accept calls v.visitEnd() after all methods are visited.
ClassWriter.visitEnd adds a closing line; RenameVisitor.visitEnd forwards it to the delegate. This builds a full pipeline: ClassReader, RenameVisitor, ClassWriter.
The full pipeline
The full pipeline works like this: ClassReader walks the class and its methods; each event first reaches RenameVisitor, which applies the transformation and forwards it to ClassWriter; ClassWriter accumulates the text. At the end visitEnd adds the closing line.
This model mirrors how ASM works in Java agents. In real ASM ClassReader parses bytecode; here we built the same flow with a name and a method list.
Practice Add visitEnd and complete the chain
Add a void visitEnd(); method to the ClassVisitor interface. Make ClassReader.accept call v.visitEnd(); after all methods are visited. Add public void visitEnd() { sb.append("End").append("\n"); } to ClassWriter. Add public void visitEnd() { delegate.visitEnd(); } to RenameVisitor. Keep main the same: reader.accept(new RenameVisitor(writer)); and System.out.println(writer.toString());.
Starter code
interface ClassVisitor {
void visitClass(String name);
void visitMethod(String name);
}
class ClassReader {
String name;
String[] methods;
ClassReader(String name, String[] methods) {
this.name = name;
this.methods = methods;
}
void accept(ClassVisitor v) {
v.visitClass(name);
for (String m : methods) v.visitMethod(m);
}
}
class ClassWriter implements ClassVisitor {
StringBuilder sb = new StringBuilder();
public void visitClass(String n) { sb.append("Class: ").append(n).append("\n"); }
public void visitMethod(String n) { sb.append("Method: ").append(n).append("\n"); }
public String toString() { return sb.toString().trim(); }
}
class RenameVisitor implements ClassVisitor {
ClassVisitor delegate;
RenameVisitor(ClassVisitor delegate) {
this.delegate = delegate;
}
public void visitClass(String n) { delegate.visitClass(n); }
public void visitMethod(String n) { delegate.visitMethod(n.replace("main", "start")); }
}
public class Main {
public static void main(String[] args) {
ClassReader reader = new ClassReader("Main", new String[]{"main"});
ClassWriter writer = new ClassWriter();
reader.accept(new RenameVisitor(writer));
System.out.println(writer.toString());
}
}Sample solution
interface ClassVisitor {
void visitClass(String name);
void visitMethod(String name);
void visitEnd();
}
class ClassReader {
String name;
String[] methods;
ClassReader(String name, String[] methods) {
this.name = name;
this.methods = methods;
}
void accept(ClassVisitor v) {
v.visitClass(name);
for (String m : methods) v.visitMethod(m);
v.visitEnd();
}
}
class ClassWriter implements ClassVisitor {
StringBuilder sb = new StringBuilder();
public void visitClass(String n) { sb.append("Class: ").append(n).append("\n"); }
public void visitMethod(String n) { sb.append("Method: ").append(n).append("\n"); }
public void visitEnd() { sb.append("End").append("\n"); }
public String toString() { return sb.toString().trim(); }
}
class RenameVisitor implements ClassVisitor {
ClassVisitor delegate;
RenameVisitor(ClassVisitor delegate) {
this.delegate = delegate;
}
public void visitClass(String n) { delegate.visitClass(n); }
public void visitMethod(String n) { delegate.visitMethod(n.replace("main", "start")); }
public void visitEnd() { delegate.visitEnd(); }
}
public class Main {
public static void main(String[] args) {
ClassReader reader = new ClassReader("Main", new String[]{"main"});
ClassWriter writer = new ClassWriter();
reader.accept(new RenameVisitor(writer));
System.out.println(writer.toString());
}
}Expected output
Class: Main Method: start End
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What is added in the combine step?
- A new thread
- A closing call with visitEnd Correct answer
- A database
- A graphics window
Explanation: visitEnd makes a closing call at the end of the traversal.
2 Complete the visitEnd declaration
void ____();
void visitEnd();
Explanation: void visitEnd(); marks the end of the traversal.
3 Summarise the project parts
| Term | Meaning |
|---|---|
ClassReader |
Walks the class |
RenameVisitor |
Renames |
ClassWriter |
Produces text |
visitEnd |
Closes the traversal |