I am trying to figure out how to take a Java pojo, and analyze its method for all other methods and function it could call. For example, here is a hardcoded example of the output. How can I make this general? I need to analyze Java objects programmatically to determine what methods they could call if executed. Example:
package com.example.analyze;
public class Main
{
private static class Foo {
public void foo(int value, Bar bar) {
if(value > 5)
bar.gaz();
}
}
private static class Bar {
public void gaz() {
System.out.println("gaz");
}
}
private static class Analyzer {
public void analyze(Object object){
System.out.println("Object method foo could call Bar method gaz");
}
}
public static void main(String[] args)
{
Foo foo = new Foo();
Analyzer analyzer = new Analyzer();
analyzer.analyze(foo);
}
}
Similarly another method which is Method2() is being defined with 'public' access specifier and 'void' as return type and inside that Method2() the Method1() is called. Hence, this program shows that a method can be called within another method as both of them belong to the same class.
Java does not support “directly” nested methods. Many functional programming languages support method within method. But you can achieve nested method functionality in Java 7 or older version by define local classes, class within method so this does compile.
But yes, what you're trying to do is possible. It's called recursion, or recursive programming. It's when a function calls itself or multiple functions call each other repeatedly. It's useful for some stuff.
To call a method in Java from another class is very simple. We can call a method from another class by just creating an object of that class inside another class. After creating an object, call methods using the object reference variable.
What you need is construct a call graph, and then ask if two nodes (a caller and callee) are connected in the call graph. This isn't an easy task.
What you need to do:
[You might be able to avoid the parsing/name-type resolution part of the above using Wala, which is constructed essentially by doing most of the above].
With the call graph, if you want to know if A can call B, find the node for A in the call graph, and see if there is a path to B.
Another note here suggests this is a 6 month task for a compiler class. I think it is 6 months for an experienced compiler person, or more (and we haven't addressed nasty problems such as class loaders and reflective calls).
I think you are better off finding a solution for this, that somebody else has already built. Likely somebody has; not so likely it is easily found or she wants to part with it. You might find implementations done in Univerisities; there are all kinds of papers written by academics (and supported by a prototype) to compute object-graphs. The down side is all those systems are prototypes, and being build by small, unpaid teams of graduates, they usually don't handle all the edge cases let alone the latest version of Java (lambdas, anyone?)
You can use ASM api to find information on a class file, The sample code gives a fair idea on how to get the method details.
Analyzer class
package sample.code.analyze;
import java.io.IOException;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class Analyzer {
public void analyze(Object object) {
ClassVisitor cv = new ClassVisitor(Opcodes.ASM4) {
@Override
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
System.out.println("Method: " + name + " -- " + desc);
return new MethodVisitor(Opcodes.ASM4) {
@Override
public void visitMethodInsn(int opcode, String owner,
String name, String desc, boolean arg4) {
System.out.println("-- opcode -- " + opcode
+ " -- owner -- " + owner + "name -- "
+ name + "desc -- " + desc);
super.visitMethodInsn(opcode, owner, name, desc, arg4);
}
};
}
};
try {
ClassReader classReader = new ClassReader(object.getClass().getCanonicalName());
classReader.accept(cv, 0);
} catch (IOException e) {
System.err.println("Something went wrong !! " + e.getMessage());
}
}
public static void main(String[] args) {
Foo foo = new Foo();
Analyzer analyzer = new Analyzer();
analyzer.analyze(foo);
}
}
Bar Class
package sample.code.analyze;
public class Bar {
public void gaz() {
System.out.println("gaz");
}
}
Foo Class
package sample.code.analyze;
import sample.code.analyze.Bar;
public class Foo {
public void foo(int value, Bar bar) {
if (value > 5) {
bar.gaz();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With