Java: Displaying all Strings used in method invocations - java

I am trying to display all the strings used in a method invocation using SOOT program analysis framework. I am able to check for StringConstant but how do I get values for RefType ? Here is the sample code :
for (Value va : iv.getInvokeExpr().getArgs()) {
System.out.println("[ARGS : TYPE] " + va.getType() + " with ");
if (va instanceof StringConstant) {
System.out.print(va + " ");
} else if (va instanceof JimpleLocal) {
JimpleLocal jl = (JimpleLocal) va;
if (jl.getType() instanceof RefType) {
RefType rt = (RefType) jl.getType();
SootClass cls = rt.getSootClass();
String clsName = cls.getName();
// recursion possible - backward analysis ?
if(clsName.equals("java.lang.String")){
System.out.print("GOT STRING CLASS - HOW TO GET THE VALUE ?");
}
}
}
}
I am new to the program analysis domain, any pointers will be of great help.
Thanks

StringConstant had a getValue Methode. Just cast The value to this type. For locals your questions does not make sense, as they are variables, not constants.

Related

Search for book using multiple criteria in java

I have this method which takes n number of arguments and search for a book in an arrayList using couple of arguments. .
How can i make it smaller?
How to sort books by category or author?
thank you in advance.
Here is my method
// search for a book using multiple criteria
static void bookSearch(String... varg) { // take varg as parameter
String title = ""; // place holders
String author = "";
if (varg.length > 1) { // check varg length
title = varg[0]; // if it is greater than 1 initialize needed arguments
author = varg[1];
} else {
title = varg[0]; // else initialize the first argument
}
for (Book book : bookList) {
/*
* if the title is the same and there is a second argument that
* match author's name print found it
*/
if (book.getTitle().equals(title)) {
if (author.isEmpty() ^ (book.getAuthor().getfName() == author)) {
System.out.println(" \"" +
title +
"\" founded at: " +
bookList.indexOf(book));
break;
}// end of if
} else if (bookList.indexOf(book) == bookList.size() - 1) {// if not found
System.out.println("cant find \"" + title);
}// end of else
} // end of for loop
} //end of search method
In Java8 you can use lambdas and functions to get flexible filter book function.
E.g. you have following Book class:
class Book {
private String author;
private String title;
}
The book filter function could look like this:
BiFunction<List<Book>, Predicate<Book>, List<Book>> BOOK_FILTER =
(books, fields) -> books.stream().filter(fields).collect(Collectors.toList());
Then, all you need is just build required Predicate and use this function.
public static List<Book> findBookByPredicate(List<Book> books, String author, String title) {
Predicate<Book> byAuthor = book -> book.getAuthor().equals(author);
Predicate<Book> byTitle = book -> book.getTitle().equals(title);
return BOOK_FILTER.apply(books, byAuthor.and(byTitle));
}
As you can see, you're not limited only certain number of Book fields. You can combine it as you like; BOOK_FILTER function stays the same.
You can default title to varg[0] and set author if varg.length is greater than one with a ternary. I would prefer a standard loop with a index counter (since otherwise you must search again to determine the index). Next, you need to complete the loop before declaring the title isn't found (I would use a boolean to maintain that state). Next, you logically need an or (not a xor) to check that the author argument is present and not empty before checking the book author. I would prefer formatted io. Like,
static void bookSearch(String... varg) {
String title = varg[0], author = varg.length > 1 ? varg[1] : "";
boolean found = false;
for (int i = 0; i < bookList.size(); i++) {
Book book = bookList.get(i);
if (book.getTitle().equals(title)
&& (author.isEmpty() || book.getAuthor().getName().equals(author))) {
System.out.printf("\"%s\" found at: %d%n", title, i);
found = true;
break;
}
}
if (!found) {
System.out.printf("cant find \"%s\"%n", title);
}
}
You can use java 8 lamda expression for this.
Ex.
List<String> lines = Arrays.asList("spring", "node", "mkyong");
//Here pass your collection and filter as per your requirement
List<String> result = lines.stream()
.filter(line -> !"mkyong".equals(line))
.collect(Collectors.toList());
Aside from using lambda expression, other way to make your code a little shorter would be to implement equals method for your Book class where you can compare two Book objects for equality by their title and author. Then instead of:
if (book.getTitle().equals(title)) {
if (author.isEmpty() ^ (book.getAuthor().getfName() == author)) {
System.out.println(" \"" + title + "\" founded at: "
+ bookList.indexOf(book));
break;
}// end of if
you can just use:
Book searchForBook = new Book();
searchForBook.setAuthor(author); //ins
searchForBook.setTitle(title);
for (Book book : bookList) {
if (book.equals(searchForBook)){
System.out.println(" \"" + title + "\" found at: "
+ bookList.indexOf(book));
break;
}
You can also make the creation of object searchForBook one line only, if you add proper constructors in your Book class.
On sorting the ArrayList - you can either make Book implement Comparable and use Collections.sort(bookList) or use a Comparator instead and use Comparator and again use Collections.sort before you use the collection, to have it sorted the way you want.
Your code can be shortened like this:
static void bookSearch (String... varg) {
String author = "";
String title = varg[0];
if (varg.length > 1) {
author = varg[1];
}
for (Book book : bookList) {
if (book.getTitle().equals (title)) && (author.isEmpty() || (book.getAuthor().getfName() == author)) {
System.out.println(" \"" + title + "\" founded at: " + bookList.indexOf(book));
return;
}
}
System.out.println("cant find \"" + title);
}
Title doesn't need to be in if and else branch. Just initialize on declaration.
Take the ternary operator from Elliot if you like
Your outer if only has the inner if (title/author). This can be replaced by &&.
Just return instead of breaking.
With the premature return, you don't need else anymore.
A boolean predicate 'matches' which does the same thing in the Book class might be preferred. Sorting can be a good idea, if you don't have to resort by different criteria often and if you search for multiple books - then it can pay off.
A boolean return or a return of the index, where the book was found, might be more flexible. But for reporting the index, I would use a classical for loop, where you get it by the same iteration.
Returning the index would allow to remove the System.outs, so that the caller can decide, how to handle the event: Order a book via net, print to stdout, output with Swing oder JavaFX or whatever.
A pure compareTo would allow efficient search algorithms to find many book in big lists fast and smooth integration in the new Stream collections.
Using varg seems to be a bad idea to me, since it opens the door wide for getting the parameter order wrong.
int bookSearch (String title, Optional[String] author) {
expresses more clearly what you want - many IDEs support parameter names.

Access Views with Reflected Class [duplicate]

I have a method:
public void extractStringFromField(Class<?> classToInspect) {
Field[] allFields = classToInspect.getDeclaredFields();
for(Field field : allFields) {
if(field.getType().isAssignableFrom(String.class)) {
System.out.println("Field name: " + field.getName());
// How to get the actual value of the string?!?!
// String strValue = ???
}
}
}
When this runs I get output like:
Field name: java.lang.String
Now how do I extract the actual string value into strValue, using reflection?
It looks like you need a reference to an instance of the class. You would want to call get and pass in the reference, casting the return to a String.
You can use get as follows:
String strValue = (String) field.get (objectReference);
In ideal situations,Class does not hold data. It merely holds the information about the structure and behavior of its instances and Instances of the Classes hold your data to use. So your extractStringFromField method can not extract values unless you pass any instances (from where it will actually extract values).
If the name of the parameter of the reference, you are passing to extract value is instance, then you can easily get what you want like bellow:
String strValue = (String)field.get(instance);
Just usefull example code for reflection fields:
Field[] fields = InsanceName.getDeclaredFields();
for (Field field : fields) { //array for fields names
System.out.println("Fields: " + Modifier.toString(field.getModifiers())); // modyfiers
System.out.println("Fields: " + field.getType().getName()); //type var name
System.out.println("Fields: " + field.getName()); //real var name
field.setAccessible(true); //var readable
System.out.println("Fields: " + field.get(InsanceName)); //get var values
System.out.println("Fields: " + field.toString()); //get "String" values
System.out.println(""); //some space for readable code
}
Just had the same issue. This Thread somewhat helped. Just for reference if somebody else stumbles upon this thread. I used the StringBuilder class to convert so basically:
StringBuilder builder = new StringBuilder();
builder.append(field.get(object))
Which has multiple advantages. One that you do not explicitly cast (which btw. causes problems with primitive types int vs. Integer) but also of being more efficient if you have multiple string operations sequentialy. In time critical code parts.
String strValue = field.getName().toString();
Full code looks like this:
public static void extractStringFromField(Class<?> Login) {
Field[] allFields = Login.getDeclaredFields();
for(Field field : allFields) {
String strValue = field.getName().toString();
// if(field.getType().isAssignableFrom(String.class)) {
System.out.println("Field name: " + strValue);
}
}

JExpression add String value as property in an if statement

I am working on a plugin to create toString statements in my project, using CodeModel.
The resulting code should look like this:
if (variable == null) {
out.append(" " + "variable = null").append("\n");
}
(out in the code above is a simple StringBuilder)
I want to use CodeModel to automatically generate new lines and tabs in the if statements, and have so far got up to this output:
if ("variable" == null) {
out.append(" " + "variable = null").append("\n");
}
The issue is the quotes surrounding the variable, which are there as I assign a JExpression literal value for the variable value. Current implementation looks like this:
private void printComplexObject(final JMethod toStringMethod, FieldOutline fo) {
String property = fo.getPropertyInfo().getName(false);
property = property.replace("\"", "");
JType type = fo.getRawType();
JBlock block = toStringMethod.body();
JConditional nullCheck = block._if(JExpr.lit(property).eq(JExpr._null())); ...}
Is anyone aware of how this could be done using JExpression or anything else from CodeModel? The only alternative I have so far is to do it with a directStatement as follows:
toStringMethod.body().directStatement("if (" + property + " == null) { out.append ...}");
The solution is to replace the JConditional nullCheck with the following:
JConditional nullCheck = block._if(JExpr.direct(property).eq(JExpr._null()));
JExpr.direct(property) instead of .lit results in variable instead of "variable" being used in this JConditional.

How to write a test in Java that checks if an object is being used in JMock or JUnit?

I'm writing some tests for a Java program, and I need to test if my object is added into a List x amount of times.
Below is a hypothetical code snippet....
ObjectWithList objectWithList = new ObjectWithList();
JMock context = new JMock();
ObjectInterface oInterfaceMock = (ObjectInterface)context.mock(ObjectInterface.class);
context.checking(new Expectations{{
oneOf(oInterfaceMock).makeSureIamOnlyStoredSomewhereOnce();
}});
context.assertIsSatisfied(); // This will be successful if objectWithList calls add only
//once.
I don't know if JUnit has a better way of testing this, any help would be much appreciated. I've been trying to do google searches, and searching through previous questions on Stack but I've had no luck.
Thank you so much everyone, any help is always appreciated!!
I would suggest doing this without JMock. you could simply write a function that counts how many times a list contains an object:
public int getCount(List<?> list, Object object) {
int count = 0;
for (Object element : list) {
if (object.equals(element)) {
count++;
}
}
return count;
}
There are other possible implementations, but this one is obviously correct. Next, you can write an assertion:
public void assertAppearsNTimes(List<?> list, Object object, int n) {
if (n == getCount(list, object)) {
return;
}
fail("Object " + object + " does not appear in list "
+ n + " times: " + list);
}

javassist Field check initialization

I am currently implementing an Annotation that forces the fields to respect a condition through javassist. I would like to check if a field is initialized when it is being read... so, currently, I am getting the classes by loading them when they are loaded by the VM through a Translator.onLoad(ClassPool pool, String className), and using an ExprEditor on each class through overriding the edit(FieldAccess arg) method. Right now, I managed to inject code to check the condition by running the following method inside onLoad :
private void processFields(FieldsAndMethods data) {
final FieldsAndMethods copy = data;
Stack<CtClass> classes = data.getThisClass();
for(CtClass cc : classes ){
try {
cc.instrument(new ExprEditor(){
#Override
public void edit(FieldAccess arg) throws CannotCompileException{
try{
CtField field = arg.getField();
if(copy.getFields().contains(field) &&
field.hasAnnotation(Assertion.class)){
Assertion a =
((Assertion)field.getAnnotation(Assertion.class))
String condition = assertion.value();
String fieldName = field.getName();
String processCondition =
transformCondition(condition, fieldName);
if(arg.isWriter()){
String code = "{if(" + evaledCondition + ")" +
"$proceed($$) ;" +
"else throw new " +
"RuntimeException(\"The assertion " +
condition + " is false.\");}";
arg.replace(code);
}else if (arg.isReader()){
//Here is where I would like to check if the field
//has been initialized...
}
}catch(ClassNotFoundException e){
System.out.println("could not find Annotation " +
Assertion.class.getName() );
}catch(NotFoundException e){
System.out.println("could not find field " +
arg.getFieldName() );
}
}
});
} catch (CannotCompileException e) {
System.out.println("Could not interpret the expression");
System.out.println(e);
}
}
}
private String transformCondition(String condition, String fieldName){
return condition.replace(fieldName, "$1");
}
Could you point me in the right direction for finding out if a field has been initialized? Notice that a field can be either a primitive or not.
Thanks in advance.
Assumptions
I'll assume the following:
By field initialized we are talking about fields that are null.
Primitive types cannot be null so no bother to check them.
The code
This example verification will work for both static and non static fields.
I've also created the code String in several lines for better readability. Being arg a FieldAccess object, you can write the following:
if (arg.isReader() && !arg.getField().getType().isPrimitive()) {
String code = "{ java.lang.Object var = $proceed();"
+ "if(var == null) {"
+ "java.lang.System.out.println(\"not initialized " + arg.getFieldName() + "\");"
+ "}"
+ "$_=var;}";
arg.replace(code);
}
Code Explanation
As you can see, in this small example I've used a few javassist identifiers, for the complete reference about this please read the javassist official tutorial (I'm linking to the section about code modifications).
Here is what each identifier used means:
$proceed() : in the case of a field access this returns the value of the field.
$_ : this is an identifier that is mandatory when editing a FieldAccess in read mode. This token holds the value that will be used to set the field.
With this information it's easy to understand the code's idea:
Put the field value into an auxiliary object named var
Check if the field is null, if so print a warning with the field name
Set the fieldname with the value (either it's null or not);
I guess this already points you to the right direction. But let me know if you need anything else.

Categories