java - How to retrieve anything inside method - java

From what i know, java cannot retrieve anything inside method. so i using option -g or -g:vars in javac.
for e.g :
class Test {
int a=0;
void method(boolean boo){
String b;
try
{
new Thread().sleep(1000);
}
catch(InterruptedException e){}
JOptionPane.showMessageDialog(null,"test");
BufferedImage image=ImageIO.read(new File("C:\\file.png"));
}
}
So, i use BCEL to retrieve local variable.
import org.apache.bcel.classfile.*;
import org.apache.bcel.Repository;
class javap
{
public static void main(String[]args)
{
try
{
JavaClass jc = Repository.lookupClass("test");
ConstantPool constantPool = jc.getConstantPool();
Method [] method=jc.getMethods();
for (Method m : method)
{
LocalVariableTable lvt=m.getLocalVariableTable();
LocalVariable[] lv=lvt.getLocalVariableTable();
for(LocalVariable l : lv)
{
System.out.println(l.getName()+" : "+l.getSignature());
}
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
But it doesn't work if variable is not initialized like String b. Additionally I want to track constructor calls like new Thread() or new File() as well as invocations of static methods and inside intialize inside JFileChooser like new File and JOptionPane too. So I want to see in output Thread, String b, JOptionPane, ImageIO, and File.
What should I do, to make them are printed in my program?

You simply cannot get the b variable, because java compilers (at least javac and ecj) do not put it into the generated class file at all: if variable is not assigned, no variable slot is allocated and it's not stored in the LocalVariableTable. You can create unused variable with longer name like String blahblah;, compile the class, open the compiled .class-file in text editor and search for blahblah string. You will not found it. So BCEL cannot help you to find the variable which is absent.
If you want to track new objects creation and static methods invocation, you can do it scanning the method bytecode. The easiest way to do it with BCEL is to utilize the MethodGen (even though you don't want to generate the new method). Here's the full code:
import org.apache.bcel.Constants;
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.ConstantMethodref;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.LocalVariable;
import org.apache.bcel.classfile.LocalVariableTable;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.NEW;
class javap
{
public static void main(String[]args)
{
try
{
JavaClass jc = Repository.lookupClass("Test");
ConstantPool constantPool = jc.getConstantPool();
Method [] method=jc.getMethods();
for (Method m : method)
{
LocalVariableTable lvt=m.getLocalVariableTable();
LocalVariable[] lv=lvt.getLocalVariableTable();
for(LocalVariable l : lv)
{
System.out.println(l.getName()+" : "+l.getSignature());
}
}
ConstantPoolGen cpg = new ConstantPoolGen(constantPool);
for(Method m : method)
{
MethodGen mg = new MethodGen(m, m.getName(), cpg);
for(InstructionHandle ih = mg.getInstructionList().getStart();
ih != null; ih = ih.getNext())
{
if(ih.getInstruction() instanceof NEW)
{
NEW newInst = ((NEW)ih.getInstruction());
String className = constantPool.getConstantString(
newInst.getIndex(), Constants.CONSTANT_Class);
System.out.println("Class instantiation: "+className);
}
if(ih.getInstruction() instanceof INVOKESTATIC)
{
INVOKESTATIC newInst = ((INVOKESTATIC)ih.getInstruction());
String className = constantPool.getConstantString(
((ConstantMethodref) constantPool
.getConstant(newInst.getIndex()))
.getClassIndex(),
Constants.CONSTANT_Class);
System.out.println("Static call: "+className);
}
}
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
The output is the following:
this : LTest;
this : LTest;
boo : Z
Class instantiation: java/lang/Thread
Static call: java/lang/Thread
Static call: javax/swing/JOptionPane
Class instantiation: java/io/File
Static call: javax/imageio/ImageIO
Note that you have java/lang/Thread twice, because new Thread() is catched as object creation and Thread.sleep() is catched as static method invocation.

Related

Reflection and Collections

I have difficulty in accessing member of a class with the parameter using a collection. For example List. This is a tiny example of a "grabber" class, which accesses a function with int parameter, but cannot find the function with the collection as its argument. This code prints a list of all members and their arguments as a diagnosis.
import static java.lang.System.out;
import static java.lang.System.err;
import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
public class grabber
{
public static void main(String args[])
{
Class<?> c=null;
try {
c=Class.forName("item");
} catch (ClassNotFoundException e) {
out.printf("?W: class item not found\n");
return;
}
try {
Object an_item=c.getDeclaredConstructor().newInstance();
out.printf("Listing methods of 'item' and their parameters\n");
Method[] allm=c.getDeclaredMethods();
for (Method m: allm)
{
String mnam=m.getName();
Type[] mptype=m.getGenericParameterTypes();
out.printf("\n\tItem Method m=%s lg of param types:%d\n",mnam, mptype.length);
for (Type t:mptype)
{
out.printf("\t arg type=%s\n",t.toString());
}
}
out.println();
Method callf2=c.getDeclaredMethod("f2", int.class);
out.printf("\tMethod callf2() is : %s\n", callf2);
Object ret=callf2.invoke(an_item,234);
List<Object> arlob=new ArrayList<Object>(); // identical to item.f1 argument
Method callf1=c.getDeclaredMethod("f1",arlob.getClass()); // this causes exception
} catch (Exception e) {
err.println("?E: Exception "+e.getClass().getName());
err.println("?E: Exception "+e.getLocalizedMessage());
e.printStackTrace(err);
return;
}
} /* main() */
} /* class */
The called class "item" is simply:
import java.util.List;
class item
{
List<Object> f1(List<Object> lob)
{
System.out.printf("\t\t------item.f1: lob.lg=%d\n",lob.size());
return lob;
}
int f2(int arg)
{
System.out.printf("\t\t------item.f2: arg=%d\n",arg);
return arg;
}
}
When I run the class grabber, the following happens, and I could not discover a way to access the function f1(List):
Listing methods of 'item' and their parameters
Item Method m=f2 lg of param types:1
arg type=int
Item Method m=f1 lg of param types:1
arg type=java.util.List<java.lang.Object>
Method callf2() is : public int item.f2(int)
------item.f2: arg=234
?E: Exception java.lang.NoSuchMethodException
?E: Exception item.f1(java.util.ArrayList)
java.lang.NoSuchMethodException: item.f1(java.util.ArrayList)
at java.lang.Class.getDeclaredMethod(Class.java:2130)
at grabber.main(grabber.java:51)
I wonder if someone found out how to access functions using abstract classes in argument list.
Simply solution would be to put known type as you already know what method is accepting as you have done in the first method call.
Change
Method callf1=c.getDeclaredMethod("f1",arlob.getClass());
to
Method callf1=c.getDeclaredMethod("f1",List.class);

How to Parse static level variable from the JAVA file?

I'm trying to Parse the static variable value from the JAVA file. But couldn't be able to parse the variable.
I've used JavaParser to Parse the code and fetch the value of variable. I got success in fetching all other class level variable and value but couldn't be able to parse the static field.
The Java File looks like ...
public class ABC {
public string variable1 = "Hello How are you?";
public boolean variable2 = false;
public static String variable3;
static{
variable3 = new String("Want to Fetch this...");
}
//Can't change this file, this is input.
public static void main(String args[]){
//....Other Code
}
}
I'm able to parse the all variables value except "variabl3". The Code of Java File looks like above Java Code and I need to Parse "variable3"'s value.
I've done below code to parse the class level variable...
import java.util.HashMap;
import java.util.List;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.VariableDeclarationExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
public class StaticCollector extends
VoidVisitorAdapter<HashMap<String, String>> {
#Override
public void visit(FieldDeclaration n, HashMap<String, String> arg) {
// TODO Auto-generated method stub
List <VariableDeclarator> myVars = n.getVariables();
for (VariableDeclarator vars: myVars){
vars.getInitializer().ifPresent(initValue -> System.out.println(initValue.toString()));
//System.out.println("Variable Name: "+vars.getNameAsString());
}
}
}
Main Method ...
public class Test {
public static void main(String[] args) {
File file = new File("filePath");
CompilationUnit compilationUnit = null;
try {
compilationUnit = JavaParser.parse(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HashMap<String, String> collector = new HashMap<String, String>();
compilationUnit.accept(new StaticCollector(), collector);
}
}
How could I parse the value of "variable3", which is static and value assigned inside static block? There might be other variable in the code but I need to find value of particular variable value (in this case Variable3).
Am I doing something wrong or i need to add some other way, please suggest.
Inspecting the AST as something that's easily readable, e.g., a DOT (GraphViz) image with PlantUML is a huge help to solve this kind of problem. See this blog on how to generate the DOT as well as other formats.
Here's the overview, with the "variable3" nodes highlighted (I just searched for it in the .dot output and put a fill color). You'll see that there are TWO spots where it occurs:
Zooming in on the node space on the right, we can see that the second sub-tree is under an InitializerDeclaration. Further down, it's part of an AssignExpr where the value is an ObjectCreationExpr:
So, I adapted your Visitor (it's an inner class to make the module self contained) and you need to override the visit(InitializerDeclaration n... method to get to where you want:
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.InitializerDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.List;
public class Test {
public static void main(String[] args) {
File file = new File("src/main/java/ABC.java");
CompilationUnit compilationUnit = null;
try {
compilationUnit = StaticJavaParser.parse(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HashMap<String, String> collector = new HashMap<String, String>();
compilationUnit.accept(new StaticCollector(), collector);
}
private static class StaticCollector extends
VoidVisitorAdapter<HashMap<String, String>> {
#Override
public void visit(FieldDeclaration n, HashMap<String, String> arg) {
List<VariableDeclarator> myVars = n.getVariables();
for (VariableDeclarator vars: myVars){
vars.getInitializer().ifPresent(initValue -> System.out.println(initValue.toString()));
//System.out.println("Variable Name: "+vars.getNameAsString());
}
}
#Override
public void visit(InitializerDeclaration n, HashMap<String, String> arg) {
List<Statement> myStatements = n.getBody().getStatements();
for (Statement s: myStatements) {
s.ifExpressionStmt(expressionStmt -> expressionStmt.getExpression()
.ifAssignExpr(assignExpr -> System.out.println(assignExpr.getValue())));
}
}
}
}
Here's the output showing additionally variable3's initialization in the static block:
"Hello How are you?"
false
new String("Want to Fetch this...")

How to get class level variable names using javaparser?

I was able to get class level variable's declarations using the following code. But I only need the variable name. This is the output I get for following code - [private boolean flag = true;]
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import java.io.FileInputStream;
public class CuPrinter{
public static void main(String[] args) throws Exception {
// creates an input stream for the file to be parsed
FileInputStream in = new FileInputStream("C:\\Users\\arosh\\IdeaProjects\\Bot_Twitter\\src\\MyBot.java");
CompilationUnit cu;
try {
// parse the file
cu = JavaParser.parse(in);
} finally {
in.close();
}
cu.accept(new ClassVisitor(), null);
}
private static class ClassVisitor extends VoidVisitorAdapter<Void> {
#Override
public void visit(ClassOrInterfaceDeclaration n, Void arg) {
/* here you can access the attributes of the method.
this method will be called for all methods in this
CompilationUnit, including inner class methods */
System.out.println(n.getFields());
super.visit(n, arg);
}
}
}
You can use the following simple regex:
final String regex = "^((private|public|protected)?\\s+)?.*\\s+(\\w+);$";
Which then can be compiled into a Pattern:
final Pattern pattern = Pattern.compile(regex);
And then finally be used in a for-loop:
for(final String field : n.getFields()){
// create a regex-matcher
final Matcher matcher = pattern.matcher(field);
// if field matches regex
if(matcher.matches()){
// get the last group -> the fieldName
final String name = matcher.group(matcher.groupCount());
System.out.println("FieldName: " + name);
}
}
You can try this. If you have more than one variables in FieldDeclarations, use one more for loop inside.
public void visit(ClassOrInterfaceDeclaration n, Void arg) {
super.visit(n, arg);
for(FieldDeclaration ff:n.getFields())
{
System.out.println(ff.getVariable(0).getName());
}
}

Going from a specific class up the tree to Object and getting their methods(without them being written more than once)

So I have a problem.My assingment untill tommorw is to make a java program,that gets a class,then writes its Name and methods,Then gets the one that it implements,does the same and continues up to Object.The problem is I have to make it so the methods don't repeat themselves.(Only the class that adds the method should print it out,the implementation of that class should no longer have it.)
I made it so it prints everything only once,but it prints it out very strangely. Here is the code:
public static void main(String[] args) {
Object o = new JRadioButton();
Class cl;
HashSet methodsnames = new HashSet();
for (cl = o.getClass(); cl != null; cl = cl.getSuperclass()) {
HashSet al = new HashSet();
System.out.println(cl.getName()+ " - ");
for (Method m : cl.getMethods()){
boolean added = methodsnames.add(m.getName());
if(added){
al.add(m.getName());}
}
al.forEach(System.out::println);
System.out.println("=============================");
}
}
With Class#getMethods you get all public methods of the class - even the public methods provided by its super-class.
I think you want to print the method only if the class also provides the implementation so you need to check the declaring class: m.getDeclaringClass().equals(cl)
Use getDeclaredMethods instead getMethods:
import java.lang.*;
import java.lang.reflect.*;
import java.util.*;
import javax.swing.*;
public class main
{
public static void main(String ...args) {
Object o = new JRadioButton();
Class cl;
HashSet methodsnames = new HashSet();
for (cl = o.getClass(); cl != null; cl = cl.getSuperclass()) {
HashSet al = new HashSet();
System.out.println(cl.getName()+ " - ");
for (Method m : cl.getDeclaredMethods()){
boolean added = methodsnames.add(m.getName());
if(added){
al.add(m.getName());
}
}
al.forEach(System.out::println);
System.out.println("=============================");
}
}
}
Check this code runing on Ideone.
This did the trick for me:
m.getDeclaringClass().equals(cl)

How to find the number of declared functions in a Java program

I am doing project in Core Java which identifies the similarity between two files, in that one part is to identify the declared functions length. I have tried the following code to find the declared methods in a given class.
import java.lang.reflect.*;
import java.io.*;
import java.lang.String.*;
public class Method1 {
private int f1(
Object p, int x) throws NullPointerException
{
if (p == null)
throw new NullPointerException();
return x;
}
public static void main(String args[])throws Exception
{
try {
Class cls = Class.forName("Anu");
int a;
Method methlist[]= cls.getDeclaredMethods();
for (int i = 0; i < methlist.length;i++) {
Method m = methlist[i];
System.out.println(methlist[i]);
System.out.println("name = " + (m.getName()).length());
}
}
catch (Throwable e) {
System.err.println(e);
}
}
}
But i have to find all the classes for a program. Shall i give input as a program since have to identify the declared methods in each class. Secondary it is working only if the given class is compiled, ie class file exist for given class.
Can any one help me for identifying the declared methods in the given program.
And i have to identify the comment lines in the program, please help me for that too.
You need to write you program to read the original code as you cannot only find the comments there. You can parse the text yourself to find comments and method signatures.
You might be able to google for libraries wich help you do this.
Using JavaCompiler class, reading file as string and execute it as below:
public class SampleTestCase {
public static void main(String[] args) {
String str = "public class sample {public static void doSomething() {System.out.println(\"Im here\");}}";
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
SimpleJavaFileObject obj = new SourceString("sample", str);
Iterable<? extends JavaFileObject> compilationUnits = Arrays
.asList(obj);
CompilationTask task = compiler.getTask(null, null, diagnostics, null,
null, compilationUnits);
boolean success = task.call();
if (success) {
try {
Method[] declaredMethods = Class.forName("sample")
.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method.getName());
}
} catch (ClassNotFoundException e) {
System.err.println("Class not found: " + e);
}
}
}
}
class SourceString extends SimpleJavaFileObject {
final String code;
SourceString(String name, String code) {
super(URI.create("string:///" + name.replace('.', '/')
+ Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
}
#Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}

Categories