Skip to content

Commit 7cf9964

Browse files
committed
Convert processing loop to stream
1 parent 9c0966a commit 7cf9964

File tree

3 files changed

+76
-31
lines changed

3 files changed

+76
-31
lines changed

src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
import org.apache.bcel.generic.ConstantPoolGen;
3737
import org.apache.bcel.generic.MethodGen;
3838

39+
import java.util.ArrayList;
40+
import java.util.List;
41+
3942
/**
4043
* The simplest of class visitors, invokes the method visitor class for each
4144
* method found.
@@ -46,7 +49,8 @@ public class ClassVisitor extends EmptyVisitor {
4649
private ConstantPoolGen constants;
4750
private String classReferenceFormat;
4851
private final DynamicCallManager DCManager = new DynamicCallManager();
49-
52+
private List<String> methodCalls = new ArrayList<>();
53+
5054
public ClassVisitor(JavaClass jc) {
5155
clazz = jc;
5256
constants = new ConstantPoolGen(clazz.getConstantPool());
@@ -73,19 +77,23 @@ public void visitConstantPool(ConstantPool constantPool) {
7377
if (constant.getTag() == 7) {
7478
String referencedClass =
7579
constantPool.constantToString(constant);
76-
System.out.println(String.format(classReferenceFormat,
77-
referencedClass));
80+
System.out.println(String.format(classReferenceFormat, referencedClass));
7881
}
7982
}
8083
}
8184

8285
public void visitMethod(Method method) {
8386
MethodGen mg = new MethodGen(method, clazz.getClassName(), constants);
8487
MethodVisitor visitor = new MethodVisitor(mg, clazz);
85-
visitor.start();
88+
methodCalls.addAll(visitor.start());
8689
}
8790

88-
public void start() {
91+
public ClassVisitor start() {
8992
visitJavaClass(clazz);
93+
return this;
94+
}
95+
96+
public List<String> methodCalls() {
97+
return this.methodCalls;
9098
}
9199
}

src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,35 @@
2828

2929
package gr.gousiosg.javacg.stat;
3030

31-
import java.io.File;
32-
import java.io.IOException;
33-
import java.util.Enumeration;
31+
import java.io.*;
32+
import java.util.*;
33+
import java.util.function.Function;
3434
import java.util.jar.JarEntry;
3535
import java.util.jar.JarFile;
36+
import java.util.stream.Stream;
37+
import java.util.stream.StreamSupport;
3638

3739
import org.apache.bcel.classfile.ClassParser;
3840

3941
/**
4042
* Constructs a callgraph out of a JAR archive. Can combine multiple archives
4143
* into a single call graph.
42-
*
44+
*
4345
* @author Georgios Gousios <gousiosg@gmail.com>
44-
*
4546
*/
4647
public class JCallGraph {
4748

4849
public static void main(String[] args) {
49-
ClassParser cp;
50+
51+
Function<ClassParser, ClassVisitor> getClassVisitor =
52+
(ClassParser cp) -> {
53+
try {
54+
return new ClassVisitor(cp.parse());
55+
} catch (IOException e) {
56+
throw new UncheckedIOException(e);
57+
}
58+
};
59+
5060
try {
5161
for (String arg : args) {
5262

@@ -57,24 +67,44 @@ public static void main(String[] args) {
5767
}
5868

5969
try (JarFile jar = new JarFile(f)) {
60-
Enumeration<JarEntry> entries = jar.entries();
61-
while (entries.hasMoreElements()) {
62-
JarEntry entry = entries.nextElement();
63-
if (entry.isDirectory())
64-
continue;
65-
66-
if (!entry.getName().endsWith(".class"))
67-
continue;
70+
Stream<JarEntry> entries = enumerationAsStream(jar.entries());
71+
72+
String methodCalls = entries.
73+
flatMap(e -> {
74+
if (e.isDirectory() || !e.getName().endsWith(".class"))
75+
return (new ArrayList<String>()).stream();
76+
77+
ClassParser cp = new ClassParser(arg, e.getName());
78+
return getClassVisitor.apply(cp).start().methodCalls().stream();
79+
}).
80+
map(s -> s + "\n").
81+
reduce(new StringBuilder(),
82+
StringBuilder::append,
83+
StringBuilder::append).toString();
6884

69-
cp = new ClassParser(arg,entry.getName());
70-
ClassVisitor visitor = new ClassVisitor(cp.parse());
71-
visitor.start();
72-
}
73-
}
85+
BufferedWriter log = new BufferedWriter(new OutputStreamWriter(System.out));
86+
log.write(methodCalls);
87+
log.close();
88+
}
7489
}
7590
} catch (IOException e) {
7691
System.err.println("Error while processing jar: " + e.getMessage());
7792
e.printStackTrace();
7893
}
7994
}
95+
96+
public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
97+
return StreamSupport.stream(
98+
Spliterators.spliteratorUnknownSize(
99+
new Iterator<T>() {
100+
public T next() {
101+
return e.nextElement();
102+
}
103+
104+
public boolean hasNext() {
105+
return e.hasMoreElements();
106+
}
107+
},
108+
Spliterator.ORDERED), false);
109+
}
80110
}

src/main/java/gr/gousiosg/javacg/stat/MethodVisitor.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
import org.apache.bcel.classfile.JavaClass;
3232
import org.apache.bcel.generic.*;
3333

34+
import java.util.ArrayList;
35+
import java.util.Collections;
36+
import java.util.List;
37+
3438
/**
3539
* The simplest of method visitors, prints any invoked method
3640
* signature for all method invocations.
@@ -43,6 +47,7 @@ public class MethodVisitor extends EmptyVisitor {
4347
private MethodGen mg;
4448
private ConstantPoolGen cp;
4549
private String format;
50+
private List<String> methodCalls = new ArrayList<>();
4651

4752
public MethodVisitor(MethodGen m, JavaClass jc) {
4853
visitedClass = jc;
@@ -63,16 +68,18 @@ private String argumentList(Type[] arguments) {
6368
return sb.toString();
6469
}
6570

66-
public void start() {
71+
public List<String> start() {
6772
if (mg.isAbstract() || mg.isNative())
68-
return;
73+
return Collections.emptyList();
74+
6975
for (InstructionHandle ih = mg.getInstructionList().getStart();
7076
ih != null; ih = ih.getNext()) {
7177
Instruction i = ih.getInstruction();
7278

7379
if (!visitInstruction(i))
7480
i.accept(this);
7581
}
82+
return methodCalls;
7683
}
7784

7885
private boolean visitInstruction(Instruction i) {
@@ -84,27 +91,27 @@ private boolean visitInstruction(Instruction i) {
8491

8592
@Override
8693
public void visitINVOKEVIRTUAL(INVOKEVIRTUAL i) {
87-
System.out.println(String.format(format,"M",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp))));
94+
methodCalls.add(String.format(format,"M",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp))));
8895
}
8996

9097
@Override
9198
public void visitINVOKEINTERFACE(INVOKEINTERFACE i) {
92-
System.out.println(String.format(format,"I",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp))));
99+
methodCalls.add(String.format(format,"I",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp))));
93100
}
94101

95102
@Override
96103
public void visitINVOKESPECIAL(INVOKESPECIAL i) {
97-
System.out.println(String.format(format,"O",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp))));
104+
methodCalls.add(String.format(format,"O",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp))));
98105
}
99106

100107
@Override
101108
public void visitINVOKESTATIC(INVOKESTATIC i) {
102-
System.out.println(String.format(format,"S",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp))));
109+
methodCalls.add(String.format(format,"S",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp))));
103110
}
104111

105112
@Override
106113
public void visitINVOKEDYNAMIC(INVOKEDYNAMIC i) {
107-
System.out.println(String.format(format,"D",i.getType(cp),i.getMethodName(cp),
114+
methodCalls.add(String.format(format,"D",i.getType(cp),i.getMethodName(cp),
108115
argumentList(i.getArgumentTypes(cp))));
109116
}
110117
}

0 commit comments

Comments
 (0)