Skip to content

Instantly share code, notes, and snippets.

@CalebWhiting
Created January 15, 2015 11:10
Show Gist options
  • Save CalebWhiting/c94fdee7ec607f2019c9 to your computer and use it in GitHub Desktop.
Save CalebWhiting/c94fdee7ec607f2019c9 to your computer and use it in GitHub Desktop.
package org.objectweb.asm.graph;
import com.revtek.util.*;
import com.revtek.util.io.*;
import org.objectweb.asm.core.*;
import org.objectweb.asm.tree.*;
import java.util.*;
import java.util.logging.*;
/**
* @author Caleb Whiting
*/
public class HierarchyGraph {
private final Library library;
private final Map<String, ClassNode> loaded = new HashMap<>();
private final Map<String, List<ClassNode>> successors = new HashMap<>();
private final Map<String, List<ClassNode>> predecessors = new HashMap<>();
public HierarchyGraph(Library library) {
this.library = library;
Stack<String> stack = new Stack<>();
stack.addAll(library.getClasses().keySet());
while (stack.size() > 0) {
String name = stack.pop();
if (name == null)
continue;
ClassNode c = getClass(name);
if (c != null) {
visit(c);
stack.push(c.superName());
c.interfaces().forEach(stack:: push);
}
}
}
private void visit(ClassNode c) {
visitParent(c, c.superName());
for (String iface : c.interfaces()) {
visitParent(c, iface);
}
}
private void visitParent(ClassNode child, String parentName) {
ClassNode parent = parentName == null ? null : getClass(parentName);
getPredecessors(child.name()).add(parent);
if (parent != null) {
List<ClassNode> parentSuccessors = getSuccessors(parent.name());
if (!parentSuccessors.contains(child)) {
parentSuccessors.add(child);
}
}
}
private ClassNode getClass(String name) {
ClassNode c;
if ((c = loaded.get(name)) == null && (c = library.getClasses().get(name)) == null) {
try {
Class clazz = Class.forName(name.replace('/', '.'));
byte[] bytes = Buffer.getBytes(clazz);
c = new ClassNode();
ClassReader reader = new ClassReader(bytes);
reader.accept(c, ClassReader.SKIP_CODE);
loaded.put(name, c);
} catch (Exception e) {
e.printStackTrace();
Logger.getLogger("Hierarchy").info("Error loading class: " + name);
}
}
return c;
}
private void print(String name, int depth, Logger log) {
ClassNode c = getClass(name);
String s = "";
for (int i = 0; i < depth; i++) s += "\t";
s += " -> ";
s += name.replace('/', '.');
if (c.superName() != null) {
s += " extends ";
s += c.superName().replace('/', '.');
}
List<String> interfaces = c.interfaces();
for (int i = 0; i < interfaces.size(); i++) {
String iface = interfaces.get(i);
s += i == 0 ? " implements " : ", ";
s += iface.replace('/', '.');
}
log.info(s);
List<ClassNode> successors = this.successors.get(name);
if (successors != null) {
for (ClassNode successor : successors) {
print(successor.name(), depth + 1, log);
}
}
}
public void print(Logger log) {
getSuccessors("java/lang/Object").stream().
filter(successor -> successor.interfaces().isEmpty()).
forEach(successor -> print(successor.name(), 0, log));
}
public List<ClassNode> getSuccessors(String name) {
List<ClassNode> successors = this.successors.get(name);
if (successors == null) {
successors = new ArrayList<>();
this.successors.put(name, successors);
}
return successors;
}
public List<ClassNode> getPredecessors(String name) {
List<ClassNode> predecessors = this.predecessors.get(name);
if (predecessors == null) {
predecessors = new ArrayList<>();
this.predecessors.put(name, predecessors);
}
return predecessors;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment