├── .gitignore
├── LICENSE
├── README.md
├── TestBytecodeCallHierarchy.jar
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── github
│ └── goblinbr
│ └── bchscanner
│ ├── JavaScanner.java
│ ├── call
│ ├── CallHierarchy.java
│ └── JavaMethod.java
│ └── visitors
│ ├── CallerClassVisitor.java
│ └── SuperClassVisitor.java
└── test
└── java
└── com
└── github
└── goblinbr
└── bchscanner
└── JavaScannerTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | .settings
3 | .classpath
4 | .project
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Rodrigo de Bona Sartor
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bytecode Call Hierarchy Scanner
2 | A java library to scan jar files and find calls to a method
3 | **This project uses [ASM](http://asm.ow2.org/) to ready the bytecode**
4 |
5 | ### Maven
6 |
7 | com.github.goblinbr
8 | bytecode-callhierarchy-scanner
9 | 1.0.1
10 |
11 |
12 | ### Example
13 | ```java
14 | import java.io.IOException;
15 | import java.util.Set;
16 |
17 | import com.github.goblinbr.bchscanner.JavaScanner;
18 | import com.github.goblinbr.bchscanner.call.CallHierarchy;
19 | import com.github.goblinbr.bchscanner.call.JavaMethod;
20 |
21 | public class App {
22 | public static void main(String[] args) {
23 | App app = new App();
24 | System.out.println("-findDirectCallersOfIntegerGetInt-");
25 | app.findDirectCallersOfIntegerGetInt();
26 | System.out.println("-findDirectCallersOfShortAnyMethod-");
27 | app.findDirectCallersOfShortAnyMethod();
28 | System.out.println("-findAllClassesThatExtendsOrImplementsCloseable-");
29 | app.findAllClassesThatExtendsOrImplementsCloseable();
30 | System.out.println("-findCallHierarchyOfIntegerDecode-");
31 | app.findCallHierarchyOfIntegerDecode();
32 | }
33 |
34 | /**
35 | * Find all callers of method getInt() of the class java.lang.Integer
36 | */
37 | private void findDirectCallersOfIntegerGetInt() {
38 | try ( JavaScanner javaScanner = new JavaScanner("C:/Program Files (x86)/java/jre7/lib/rt.jar") ){
39 | Set callers = javaScanner.findCallersOfMethod("java/lang/Integer", "int intValue()");
40 | for( JavaMethod caller : callers ){
41 | System.out.println( "Class: " + caller.getPackageName() + "." + caller.getSimpleClassName()
42 | + " Method: " + caller.getMethodName()
43 | + " Method description: " + caller.getMethodDesc() );
44 | }
45 |
46 | System.out.println( "Found " + callers.size() + " calls to Integer.intValue()" );
47 | }
48 | catch (IOException e) {
49 | e.printStackTrace();
50 | }
51 | }
52 |
53 | /**
54 | * Find all callers of any method of the class java.lang.Short
55 | */
56 | private void findDirectCallersOfShortAnyMethod() {
57 | try ( JavaScanner javaScanner = new JavaScanner("C:/Program Files (x86)/java/jre7/lib/rt.jar") ){
58 | Set callers = javaScanner.findCallersOfAnyMethod("java/lang/Short");
59 | System.out.println( "Found " + callers.size() + " calls to any method of Short" );
60 | }
61 | catch (IOException e) {
62 | e.printStackTrace();
63 | }
64 | }
65 |
66 | /**
67 | * Find all classes/interfaces that implements or extends java.io.Closable
68 | */
69 | private void findAllClassesThatExtendsOrImplementsCloseable() {
70 | try ( JavaScanner javaScanner = new JavaScanner("C:/Program Files (x86)/java/jre7/lib/rt.jar") ){
71 | Set classNames = javaScanner.findAllClassesThatExtendsOrImplements("java/io/Closeable");
72 | for( String className : classNames ){
73 | System.out.println( "Name: " + className );
74 | }
75 |
76 | System.out.println( "Found " + classNames.size() + " classes that implements or extends Closeable" );
77 | }
78 | catch (IOException e) {
79 | e.printStackTrace();
80 | }
81 | }
82 |
83 | /**
84 | * Find call hierarchy of method decode(String) of the class java.lang.Integer
85 | */
86 | private void findCallHierarchyOfIntegerDecode() {
87 | try ( JavaScanner javaScanner = new JavaScanner("C:/Program Files (x86)/java/jre7/lib/rt.jar") ){
88 | CallHierarchy callHierarchy = javaScanner.findCallHierarchy("java/lang/Integer","Integer decode(String)");
89 | printCallHierarchy( callHierarchy, 0 );
90 | }
91 | catch (IOException e) {
92 | e.printStackTrace();
93 | }
94 | }
95 |
96 | private void printCallHierarchy(CallHierarchy callHierarchy, int level) {
97 | JavaMethod javaMethod = callHierarchy.getMethod();
98 | String levelPrefix = "";
99 | for( int i = 0; i < level; i++ ){
100 | levelPrefix += "|";
101 | }
102 | levelPrefix += "-";
103 | System.out.println( levelPrefix + " Class: " + javaMethod.getPackageName() + "." + javaMethod.getSimpleClassName()
104 | + " Method: " + javaMethod.getMethodName()
105 | + " Method description: " + javaMethod.getMethodDesc() );
106 |
107 | for( CallHierarchy caller : callHierarchy.getCallers() ){
108 | printCallHierarchy( caller, level + 1 );
109 | }
110 | }
111 | }
112 | ```
113 |
--------------------------------------------------------------------------------
/TestBytecodeCallHierarchy.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goblinbr/BytecodeCallHierarchyScanner/92f2a406b6a21cf9865276915a8993503f8f39a9/TestBytecodeCallHierarchy.jar
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | com.github.goblinbr
5 | bytecode-callhierarchy-scanner
6 | 1.0.1
7 | jar
8 |
9 | Bytecode Call Hierarchy Scanner
10 | A java library to scan jar files and find calls to a method.
11 | https://github.com/goblinbr/BytecodeCallHierarchyScanner
12 |
13 |
14 |
15 | MIT License
16 | http://www.opensource.org/licenses/mit-license.php
17 |
18 |
19 |
20 |
21 |
22 | Rodrigo de Bona Sartor
23 | rodrigo.goblin@gmail.com
24 |
25 |
26 |
27 |
28 |
29 |
30 | scm:git:git@github.com:goblinbr/BytecodeCallHierarchyScanner.git
31 | scm:git:git@github.com:goblinbr/BytecodeCallHierarchyScanner.git
32 | https://github.com/goblinbr/BytecodeCallHierarchyScanner.git
33 |
34 |
35 |
36 | UTF-8
37 |
38 |
39 |
40 |
41 | ossrh
42 | https://oss.sonatype.org/content/repositories/snapshots
43 |
44 |
45 | ossrh
46 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
47 |
48 |
49 |
50 |
51 |
52 |
53 | org.apache.maven.plugins
54 | maven-source-plugin
55 | 2.4
56 |
57 |
58 | attach-sources
59 |
60 | jar-no-fork
61 |
62 |
63 |
64 |
65 |
66 | org.apache.maven.plugins
67 | maven-javadoc-plugin
68 | 2.10.3
69 |
70 |
71 | attach-javadocs
72 |
73 | jar
74 |
75 |
76 |
77 |
78 |
79 | org.apache.maven.plugins
80 | maven-gpg-plugin
81 | 1.5
82 |
83 |
84 | sign-artifacts
85 | verify
86 |
87 | sign
88 |
89 |
90 |
91 |
92 |
93 | org.sonatype.plugins
94 | nexus-staging-maven-plugin
95 | 1.6.7
96 | true
97 |
98 | ossrh
99 | https://oss.sonatype.org/
100 | true
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | org.ow2.asm
109 | asm
110 | 5.1
111 |
112 |
113 |
114 | org.ow2.asm
115 | asm-commons
116 | 5.1
117 |
118 |
119 |
120 | junit
121 | junit
122 | 4.12
123 | test
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/src/main/java/com/github/goblinbr/bchscanner/JavaScanner.java:
--------------------------------------------------------------------------------
1 | package com.github.goblinbr.bchscanner;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.Closeable;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.util.Enumeration;
8 | import java.util.Set;
9 | import java.util.jar.JarEntry;
10 | import java.util.jar.JarFile;
11 |
12 | import org.objectweb.asm.ClassReader;
13 | import org.objectweb.asm.commons.Method;
14 |
15 | import com.github.goblinbr.bchscanner.call.CallHierarchy;
16 | import com.github.goblinbr.bchscanner.call.JavaMethod;
17 | import com.github.goblinbr.bchscanner.visitors.CallerClassVisitor;
18 | import com.github.goblinbr.bchscanner.visitors.SuperClassVisitor;
19 |
20 | /**
21 | * A class that scans jar files and finds calls to a method
22 | *
23 | * @author Rodrigo de Bona Sartor
24 | */
25 | public class JavaScanner implements Closeable {
26 |
27 | private JarFile jarFile;
28 |
29 | /**
30 | * Create a new JavaScanner with the JarFile containing at jarPath
31 | * @param jarPath OS path to the jar file that contains the class
32 | * @throws IOException if an I/O error has occurred
33 | * @throws SecurityException if access to the file is denied
34 | * by the SecurityManager
35 | */
36 | public JavaScanner(String jarPath) throws IOException {
37 | this.jarFile = new JarFile(jarPath);
38 | }
39 |
40 | /**
41 | * Find callers of any method of the class className or any subclass
42 | * @param className the full class name. ex: "java/lang/Integer"
43 | * @return a Set with the callers or a empty Set if no one was found
44 | * @throws IOException if an I/O error has occurred
45 | */
46 | public Set findCallersOfAnyMethod( String className ) throws IOException {
47 | return findCallersOfMethod( className, null );
48 | }
49 |
50 | /**
51 | * Find callers of methodSignature of the class className or any subclass
52 | * @param className the full class name. ex: "java/lang/Integer"
53 | * @param methodSignature method signature. ex: "java.lang.Integer methodName(java.lang.Integer)"
54 | * @return a Set with the callers or a empty Set if no one was found
55 | * @throws IOException if an I/O error has occurred
56 | */
57 | public Set findCallersOfMethod( String className, String methodSignature ) throws IOException {
58 | String methodName = "";
59 | String methodDesc = "";
60 | if( methodSignature != null ){
61 | Method method = Method.getMethod(methodSignature);
62 | methodName = method.getName();
63 | methodDesc = method.getDescriptor();
64 | }
65 |
66 | return findCallersOfMethod( className, methodName, methodDesc );
67 | }
68 |
69 | private Set findCallersOfMethod(String className, String methodName, String methodDesc) throws IOException {
70 | Set classNames = findAllClassesThatExtendsOrImplements(className);
71 |
72 | CallerClassVisitor callerClassVisitor = new CallerClassVisitor( classNames, methodName, methodDesc );
73 | Enumeration entries = this.jarFile.entries();
74 | while (entries.hasMoreElements()) {
75 | JarEntry entry = entries.nextElement();
76 |
77 | if (entry.getName().endsWith(".class")) {
78 | InputStream stream = new BufferedInputStream(this.jarFile.getInputStream(entry), 1024);
79 | ClassReader reader = new ClassReader(stream);
80 |
81 | reader.accept(callerClassVisitor, 0);
82 |
83 | stream.close();
84 | }
85 | }
86 | return callerClassVisitor.getCallers();
87 | }
88 |
89 | /**
90 | * Find call hierarchy of methodSignature of the class className or any subclass
91 | * @param className the full class name. ex: "java/lang/Integer"
92 | * @param methodSignature method signature. ex: "java.lang.Integer methodName(java.lang.Integer)"
93 | * @return a CallHierarchy starting with the parameter method
94 | * @throws IOException if an I/O error has occurred
95 | */
96 | public CallHierarchy findCallHierarchy( String className, String methodSignature ) throws IOException {
97 | String methodName = "";
98 | String methodDesc = "";
99 | if( methodSignature != null ){
100 | Method method = Method.getMethod(methodSignature);
101 | methodName = method.getName();
102 | methodDesc = method.getDescriptor();
103 | }
104 |
105 | CallHierarchy callHierarchy = new CallHierarchy(null, className, methodName, methodDesc);
106 |
107 | findCallHierarchy( callHierarchy );
108 |
109 | return callHierarchy;
110 | }
111 |
112 | private void findCallHierarchy(CallHierarchy callHierarchy) throws IOException {
113 | JavaMethod method = callHierarchy.getMethod();
114 | Set callers = findCallersOfMethod( method.getClassName(), method.getMethodName(), method.getMethodDesc() );
115 | for( JavaMethod caller : callers ){
116 | if( !callHierarchy.containsCall( caller ) ){
117 |
118 | CallHierarchy callHierarchyCaller = new CallHierarchy(callHierarchy, caller.getClassName(), caller.getMethodName(), caller.getMethodDesc() );
119 | callHierarchy.addCaller( callHierarchyCaller );
120 | }
121 | }
122 |
123 | for( CallHierarchy caller : callHierarchy.getCallers() ){
124 | findCallHierarchy(caller);
125 | }
126 | }
127 |
128 | /**
129 | * Find call hierarchy of any method of the class className or any subclass
130 | * @param className the full class name. ex: "java/lang/Integer"
131 | * @return a CallHierarchy starting with the parameter class
132 | * @throws IOException if an I/O error has occurred
133 | */
134 | public CallHierarchy findCallHierarchyOfAnyMethod(String className) throws IOException {
135 | return findCallHierarchy(className, null);
136 | }
137 |
138 | /**
139 | * Find all classes that extends or implements class/interface className
140 | * @param className the full class name. ex: "java/lang/Integer"
141 | * @return a Set with all classes names, className will be at the Set too,
142 | * it will always return a Set with at least className inside
143 | * @throws IOException if an I/O error has occurred
144 | */
145 | public Set findAllClassesThatExtendsOrImplements( String className ) throws IOException{
146 | SuperClassVisitor superClassVisitor = new SuperClassVisitor( className );
147 | int qtyClass;
148 | do{
149 | qtyClass = superClassVisitor.getClassNames().size();
150 |
151 | Enumeration entries = this.jarFile.entries();
152 | while (entries.hasMoreElements()) {
153 | JarEntry entry = entries.nextElement();
154 |
155 | if (entry.getName().endsWith(".class")) {
156 | InputStream stream = new BufferedInputStream(this.jarFile.getInputStream(entry), 1024);
157 | ClassReader reader = new ClassReader(stream);
158 |
159 | reader.accept(superClassVisitor, 0);
160 |
161 | stream.close();
162 | }
163 | }
164 | } while( qtyClass != superClassVisitor.getClassNames().size() );
165 |
166 | return superClassVisitor.getClassNames();
167 | }
168 |
169 | /**
170 | * Closes the jar file
171 | * @throws IOException if an I/O error has occurred
172 | */
173 | public void close() throws IOException {
174 | if( this.jarFile != null ){
175 | this.jarFile.close();
176 | }
177 | }
178 |
179 |
180 | }
181 |
--------------------------------------------------------------------------------
/src/main/java/com/github/goblinbr/bchscanner/call/CallHierarchy.java:
--------------------------------------------------------------------------------
1 | package com.github.goblinbr.bchscanner.call;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class CallHierarchy implements Comparable {
7 |
8 | private JavaMethod method;
9 |
10 | private CallHierarchy callee;
11 | private List callers;
12 |
13 | public CallHierarchy(CallHierarchy callee, String className, String methodName, String methodDesc) {
14 | this.callee = callee;
15 | this.method = new JavaMethod(className, methodName, methodDesc);
16 | this.callers = new ArrayList();
17 | }
18 |
19 | public void addCaller(CallHierarchy caller) {
20 | this.callers.add(caller);
21 | }
22 |
23 | public CallHierarchy getCallee() {
24 | return callee;
25 | }
26 |
27 | public List getCallers() {
28 | return callers;
29 | }
30 |
31 | public JavaMethod getMethod() {
32 | return method;
33 | }
34 |
35 | @Override
36 | public int hashCode() {
37 | return this.method.hashCode();
38 | }
39 |
40 | @Override
41 | public boolean equals(Object obj) {
42 | return obj != null && obj.getClass() == CallHierarchy.class && obj.hashCode() == this.hashCode();
43 | }
44 |
45 | public int compareTo(CallHierarchy o) {
46 | return this.method.compareTo(o.method);
47 | }
48 |
49 | @Override
50 | public String toString() {
51 | String spaces = "";
52 | CallHierarchy c = this.callee;
53 | while( c != null ){
54 | spaces += " ";
55 | c = c.getCallee();
56 | }
57 | return spaces + this.method.toString();
58 | }
59 |
60 | public boolean containsCall(JavaMethod method) {
61 | boolean contains = this.method.equals(method);
62 | if( !contains && callee != null ){
63 | contains = callee.containsCall(method);
64 | }
65 | return contains;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/github/goblinbr/bchscanner/call/JavaMethod.java:
--------------------------------------------------------------------------------
1 | package com.github.goblinbr.bchscanner.call;
2 |
3 | public class JavaMethod implements Comparable {
4 |
5 | private String className;
6 | private String methodName;
7 | private String methodDesc;
8 |
9 | public JavaMethod(String className, String methodName, String methodDesc) {
10 | this.className = className;
11 | this.methodName = methodName;
12 | this.methodDesc = methodDesc;
13 | }
14 |
15 | public String getClassName() {
16 | return className;
17 | }
18 |
19 | public String getMethodDesc() {
20 | return methodDesc;
21 | }
22 |
23 | public String getMethodName() {
24 | return methodName;
25 | }
26 |
27 | public String getSimpleClassName() {
28 | String simpleName = this.className;
29 | int index = this.className.lastIndexOf("/");
30 | if( index >= 0 ){
31 | simpleName = this.className.substring( index + 1 );
32 | }
33 | return simpleName;
34 | }
35 |
36 | public String getPackageName() {
37 | String packageName = "";
38 | int index = this.className.lastIndexOf("/");
39 | if( index >= 0 ){
40 | packageName = this.className.substring( 0, index ).replace("/", ".");
41 | }
42 | return packageName;
43 | }
44 |
45 | @Override
46 | public int hashCode() {
47 | return (className + methodName + methodDesc).hashCode();
48 | }
49 |
50 | @Override
51 | public boolean equals(Object obj) {
52 | return obj != null && obj.getClass() == JavaMethod.class && obj.hashCode() == this.hashCode();
53 | }
54 |
55 | public int compareTo(JavaMethod o) {
56 | int comp = this.className.compareTo(o.className);
57 | if( comp == 0 ){
58 | comp = this.methodName.compareTo(o.methodName);
59 | if( comp == 0 ){
60 | comp = this.methodDesc.compareTo(o.methodDesc);
61 | }
62 | }
63 | return comp;
64 | }
65 |
66 | @Override
67 | public String toString() {
68 | return this.className + ( ( this.methodName.equals("") ) ? "" : "." + this.methodName + this.methodDesc );
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/github/goblinbr/bchscanner/visitors/CallerClassVisitor.java:
--------------------------------------------------------------------------------
1 | package com.github.goblinbr.bchscanner.visitors;
2 |
3 | import java.util.Collection;
4 | import java.util.Set;
5 | import java.util.TreeSet;
6 |
7 | import org.objectweb.asm.ClassVisitor;
8 | import org.objectweb.asm.MethodVisitor;
9 | import org.objectweb.asm.Opcodes;
10 |
11 | import com.github.goblinbr.bchscanner.call.JavaMethod;
12 |
13 | public class CallerClassVisitor extends ClassVisitor {
14 |
15 | private final ThisMethodVisitor methodVisitor;
16 |
17 | public CallerClassVisitor( Collection classesAndSuperClasses, String methodName, String methodDesc ) {
18 | super(Opcodes.ASM5);
19 | this.methodVisitor = new ThisMethodVisitor(classesAndSuperClasses, methodName, methodDesc);
20 | }
21 |
22 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
23 | this.methodVisitor.setActualClassName(name);
24 | }
25 |
26 | @Override
27 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
28 | this.methodVisitor.setActualMethodName(name);
29 | this.methodVisitor.setActualMethodDesc(desc);
30 |
31 | return this.methodVisitor;
32 | }
33 |
34 | public Set getCallers() {
35 | return this.methodVisitor.getCallers();
36 | }
37 |
38 | class ThisMethodVisitor extends MethodVisitor {
39 |
40 | private Set callers;
41 | private Collection classesAndSuperClasses;
42 | private String methodName;
43 | private String methodDesc;
44 |
45 | private String actualClassName;
46 | private String actualMethodName;
47 | private String actualMethodDesc;
48 |
49 | public ThisMethodVisitor( Collection classesAndSuperClasses, String methodName, String methodDesc ) {
50 | super(Opcodes.ASM5);
51 | this.callers = new TreeSet();
52 | this.classesAndSuperClasses = classesAndSuperClasses;
53 | this.methodName = methodName;
54 | this.methodDesc = methodDesc;
55 | }
56 |
57 | public void setActualClassName(String actualClassName) {
58 | this.actualClassName = actualClassName;
59 | }
60 |
61 | public void setActualMethodName(String actualMethodName) {
62 | this.actualMethodName = actualMethodName;
63 | }
64 |
65 | public void setActualMethodDesc(String actualMethodDesc) {
66 | this.actualMethodDesc = actualMethodDesc;
67 | }
68 |
69 | public Set getCallers() {
70 | return callers;
71 | }
72 |
73 | @Override
74 | public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
75 | if ( this.classesAndSuperClasses.contains(owner) && (this.methodName == null || this.methodName.equals("") || name.equals(this.methodName) && desc.equals(this.methodDesc))) {
76 | JavaMethod caller = new JavaMethod(this.actualClassName, this.actualMethodName, this.actualMethodDesc);
77 | this.callers.add(caller);
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/com/github/goblinbr/bchscanner/visitors/SuperClassVisitor.java:
--------------------------------------------------------------------------------
1 | package com.github.goblinbr.bchscanner.visitors;
2 |
3 | import java.util.Set;
4 | import java.util.TreeSet;
5 |
6 | import org.objectweb.asm.ClassVisitor;
7 | import org.objectweb.asm.Opcodes;
8 |
9 | public class SuperClassVisitor extends ClassVisitor {
10 |
11 | private Set classNames;
12 |
13 | public SuperClassVisitor( String classNameToSearch ) {
14 | super(Opcodes.ASM5);
15 | this.classNames = new TreeSet();
16 | this.classNames.add(classNameToSearch);
17 | }
18 |
19 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
20 | if( superName != null && this.classNames.contains(superName) ){
21 | this.classNames.add(name);
22 | }
23 | else {
24 | for( String interfaceName : interfaces ){
25 | if( this.classNames.contains(interfaceName) ){
26 | this.classNames.add(name);
27 | break;
28 | }
29 | }
30 | }
31 | }
32 |
33 | public Set getClassNames() {
34 | return classNames;
35 | }
36 | }
--------------------------------------------------------------------------------
/src/test/java/com/github/goblinbr/bchscanner/JavaScannerTest.java:
--------------------------------------------------------------------------------
1 | package com.github.goblinbr.bchscanner;
2 |
3 | import java.io.IOException;
4 | import java.util.List;
5 | import java.util.Set;
6 |
7 | import org.junit.AfterClass;
8 | import org.junit.Assert;
9 | import org.junit.BeforeClass;
10 | import org.junit.Test;
11 |
12 | import com.github.goblinbr.bchscanner.JavaScanner;
13 | import com.github.goblinbr.bchscanner.call.CallHierarchy;
14 | import com.github.goblinbr.bchscanner.call.JavaMethod;
15 |
16 | public class JavaScannerTest {
17 |
18 | private static JavaScanner javaScanner;
19 |
20 | @BeforeClass
21 | public static void before() {
22 | try {
23 | javaScanner = new JavaScanner("TestBytecodeCallHierarchy.jar");
24 | } catch (IOException e) {
25 | e.printStackTrace();
26 | }
27 | }
28 |
29 | @AfterClass
30 | public static void after() {
31 | try {
32 | javaScanner.close();
33 | } catch (IOException e) {
34 | e.printStackTrace();
35 | }
36 | }
37 |
38 | @Test
39 | public void findAllClassesThatExtendsOrImplementsAClassShouldReturnTwo(){
40 | try {
41 | Assert.assertEquals(2,javaScanner.findAllClassesThatExtendsOrImplements("com/github/goblinbr/testbytecode/AClassImplementsDInterface").size());
42 | } catch (IOException e) {
43 | e.printStackTrace();
44 | Assert.fail("Should not throw an exception");
45 | }
46 | }
47 |
48 | @Test
49 | public void findAllClassesThatExtendsOrImplementsDInterfaceShouldReturnFour(){
50 | try {
51 | Assert.assertEquals(4,javaScanner.findAllClassesThatExtendsOrImplements("com/github/goblinbr/testbytecode/DInterface").size());
52 | } catch (IOException e) {
53 | e.printStackTrace();
54 | Assert.fail("Should not throw an exception");
55 | }
56 | }
57 |
58 | @Test
59 | public void findAllClassesThatExtendsOrImplementsBClassShouldReturnOne(){
60 | try {
61 | Assert.assertEquals(1,javaScanner.findAllClassesThatExtendsOrImplements("com/github/goblinbr/testbytecode/BClassExtendsAClass").size());
62 | } catch (IOException e) {
63 | e.printStackTrace();
64 | Assert.fail("Should not throw an exception");
65 | }
66 | }
67 |
68 | @Test
69 | public void findAllClassesThatExtendsOrImplementsInvalidClassShouldReturnOne(){
70 | try {
71 | Assert.assertEquals(1,javaScanner.findAllClassesThatExtendsOrImplements("com/github/goblinbr/testbytecode/InvalidClass").size());
72 | } catch (IOException e) {
73 | e.printStackTrace();
74 | Assert.fail("Should not throw an exception");
75 | }
76 | }
77 |
78 | @Test
79 | public void findCallersOfDInterfaceGetAShouldReturnFour(){
80 | try {
81 | Set callers = javaScanner.findCallersOfMethod("com/github/goblinbr/testbytecode/DInterface", "int getA()");
82 | Assert.assertEquals(4,callers.size());
83 | } catch (IOException e) {
84 | e.printStackTrace();
85 | Assert.fail("Should not throw an exception");
86 | }
87 | }
88 |
89 | @Test
90 | public void findCallersOfGClassUseEClassShouldReturnOne(){
91 | try {
92 | Set callers = javaScanner.findCallersOfMethod("com/github/goblinbr/testbytecode/GClassUsesAClassAndEClass", "Integer useEClass(Integer)");
93 | Assert.assertEquals(1,callers.size());
94 | } catch (IOException e) {
95 | e.printStackTrace();
96 | Assert.fail("Should not throw an exception");
97 | }
98 | }
99 |
100 | @Test
101 | public void findCallersOfInvalidClassShouldReturnZero(){
102 | try {
103 | Set callers = javaScanner.findCallersOfMethod("com/github/goblinbr/testbytecode/InvalidClass", "Integer useEClass(Integer)");
104 | Assert.assertEquals(0,callers.size());
105 | } catch (IOException e) {
106 | e.printStackTrace();
107 | Assert.fail("Should not throw an exception");
108 | }
109 | }
110 |
111 | @Test
112 | public void findCallersOfInvalidMethodShouldReturnZero(){
113 | try {
114 | Set callers = javaScanner.findCallersOfMethod("com/github/goblinbr/testbytecode/GClassUsesAClassAndEClass", "Integer invalidMethod(Integer)");
115 | Assert.assertEquals(0,callers.size());
116 | } catch (IOException e) {
117 | e.printStackTrace();
118 | Assert.fail("Should not throw an exception");
119 | }
120 | }
121 |
122 | @Test
123 | public void findCallersOfClassGClassAnyMethodShouldReturnOne(){
124 | try {
125 | Set callers = javaScanner.findCallersOfAnyMethod("com/github/goblinbr/testbytecode/GClassUsesAClassAndEClass");
126 | Assert.assertEquals(1,callers.size());
127 | } catch (IOException e) {
128 | e.printStackTrace();
129 | Assert.fail("Should not throw an exception");
130 | }
131 | }
132 |
133 | @Test
134 | public void findCallersOfClassDInterfaceAnyMethodShouldReturnFive(){
135 | try {
136 | Set callers = javaScanner.findCallersOfAnyMethod("com/github/goblinbr/testbytecode/DInterface");
137 | Assert.assertEquals(5,callers.size());
138 | } catch (IOException e) {
139 | e.printStackTrace();
140 | Assert.fail("Should not throw an exception");
141 | }
142 | }
143 |
144 | @Test
145 | public void findCallHierarchyOfClassDInterfaceShouldReturnFive(){
146 | try {
147 | CallHierarchy callHierarchy = javaScanner.findCallHierarchyOfAnyMethod("com/github/goblinbr/testbytecode/DInterface");
148 | List callers = callHierarchy.getCallers();
149 | Assert.assertEquals(5,callers.size());
150 | } catch (IOException e) {
151 | e.printStackTrace();
152 | Assert.fail("Should not throw an exception");
153 | }
154 | }
155 |
156 | @Test
157 | public void findCallersOfJClassCreateIClassShouldReturnOne(){
158 | try {
159 | Set callers = javaScanner.findCallersOfMethod("com/github/goblinbr/testbytecode/JClassUsesIClass", "com.github.goblinbr.testbytecode.IClass createIClass(com.github.goblinbr.testbytecode.IClass,com.github.goblinbr.testbytecode.IClass)");
160 | Assert.assertEquals(1,callers.size());
161 | } catch (IOException e) {
162 | e.printStackTrace();
163 | Assert.fail("Should not throw an exception");
164 | }
165 | }
166 |
167 | }
168 |
--------------------------------------------------------------------------------