JExpression add String value as property in an if statement - java

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.

Related

What does the following code analysis mean?

I have an object instantiated like the following in only one place in my code(AggregateFunctions).
private String selectColumns() {
String query = "SELECT ";
if (this.distinctResults) {
query = query + "DISTINCT ";
}
SelectColumn selectColumn = new SelectColumn(this);
if (!this.applyAggregation) {
for (Object object : this.columns) {
query = selectColumn.selectColumn(query, object);
}
} else {
AggregateFunctions aggregateFunctions = new AggregateFunctions(this);
query = query + aggregateFunctions.select();
}
//Remove extra ', '
query = query.substring(0, query.length() - 2) + " FROM ";
return query;
}
The constructors:
public AggregateFunctions(#NotNull SqlQueryGenerator sqlQueryGenerator) {
this.spaceEncloser = sqlQueryGenerator.getSpaceEncloser();
this.selectColumn = new SelectColumn(sqlQueryGenerator);
JSONObject formData = sqlQueryGenerator.getFormData();
this.columns = formData.getJSONArray("columns");
this.aggregateJson = formData.getJSONObject("functions").getJSONArray("aggregate");
this.aggregatesList = new ArrayList<Aggregate>();
prepareAggregates();
this.query = new StringBuilder();
}
public SelectColumn(SqlQueryGenerator sqlQueryGenerator) {
this.sqlQueryGenerator = sqlQueryGenerator;
}
But IntelliJ Code Analysis says the following about recursive calls. Basically I didn't understand the meaning. Can anyone elaborate to help me understand?
Problem synopsis
Constructor has usage(s) but they all belong to recursive calls chain that has no members reachable from entry points.   
Problem resolution
Safe delete
Comment out
Add as Entry Point
This is a warning from the Unused declaration inspection. IntelliJ IDEA thinks the constructor is not reachable from any entry points. The constructor is not unused however, but the usages are themselves unreachable.
If this is not the case for your code, it may be a bug in IntelliJ IDEA.
Probably in the constructor of AggregateFunctions in the code that you call you go back to the method selectColumns() in the other class. This way a recurrsion is never going to end.
My guess is that either here
JSONObject formData = sqlQueryGenerator.getFormData();
Or somewhere in here:
this.selectColumn = new SelectColumn(sqlQueryGenerator);
You go to the previous class and to the same method that creates a new aggreggate and a loop is happening.
You call the AggregateFunction with this - which is the same object. But then in the constructor you call methods of this. Check these methods and if any of them has another creation of AggregateFunction object - there is your problem.
I had this issue and it was because the object was not used anywhere else

JAVA IF Else variables

public void actionPerformed(ActionEvent arg0) {
String employeeInput;
String assetInput;
String userInput = txtUserInput.getText();
userInput = userInput.toLowerCase();
if (userInput.startsWith("emp")){
//String employeeInput = null;
employeeInput = userInput.replaceAll("\\s","");
txtUserInput.setText("");
JOptionPane.showMessageDialog(frame, "The Scan was " );
}else if (userInput.startsWith("u")){
assetInput = userInput;
assetInput.replaceAll("\\s","");
txtUserInput.setText("");
System.out.println("Employee ID is " + **employeeInput**); //asks for employeeInput to be declared.
JOptionPane.showMessageDialog(frame, "The Scan was " + assetInput);
I want the employeeInput to be filled and saved, untill it is replaced by another employeeInput. The problem I'm having is when getting the item input, the employeeInput is now missing. What is the way to do this?
Thank you, for your help
employeeInput is a method variable, so everytime you exit the method you will lose the reference to it.
The obvious thing to try is turn employeeInput into a member variable. Just declare it at the top of your class.
Better yet may be to persist that value to a database.
The compiler doesn't know that the first condition has already been met. Nor, do I. But, you could change
String employeeInput; // <-- may not have been initialized
to a default value (possibly even explicitly null), here the empty String "".
String employeeInput = "";
It doesn't look like your employeeInput variable is 'missing' or could be removed after any other variable is set. So its most likely you aren't initializing your variables when they're defined.
Try initializing them like
String employeeInput = ""; // or = null
String assetInput = ""; // or = null
String userInput = txtUserInput.getText().toLowerCase();
And your problem should be solved. The compiler might also be giving you a warning about this.
You might also want to try removing this txtUserInput.setText(""); line to test for problems.
Edit:
If you are trying to access this variable after your method has finished executing then it will be wiped so instead of putting it in your method declare it in your class like public class Name{
public /*static*/ String employeeInput = ""; //or null
}

Java: Displaying all Strings used in method invocations

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.

How to check the type of variable that would store a given value (contained in a String)?

How Can I check the Type of a variable . in this way :
Pseudo Code :
do{
VARIABLE = JOptionPane.showInputDialog(null,"X = ");
}while(VARIABLE != Integer);
Set_X(VARIABLE);
In this case, your VARIABLE variable will be of type String.
You can try/catch Integer.valueOf on that variable to get its Integer value.
If a NumberFormatException is thrown, it means the user input cannot be converted to Integer.
For instance (draft code):
// initializing Integer interpretation
Integer input = null;
// infinite loop - breaks only once user has entered a valid integer-parseable value
while (true) {
// trying to convert user input after showing option pane
try {
input = Integer.valueOf(JOptionPane.showInputDialog(null, "X = "));
// breaking infinite loop
break;
}
// conversion unsuccessful
catch (NumberFormatException nfe) {
// TODO handle any error message if you need to
}
}
You can't check it for any type, obviously. You can, however, try to parse it using parsers of known types and, if parsing succeeds for one, cast it to that type and move on.
For example, the integer-parsing helper function is Integer.parseInt(String). Unfortunately, it throws an exception on failure (which will make your code ugly and slow at that point) and I'm not sure there are alternatives in the base library (equivalent to, say, C#'s TryParse).
The following example uses a Class object to print the class name of an object:
void printClassName(Object obj) {
System.out.println("The class of " + obj +
" is " + obj.getClass().getName());
}
Hence this code will perform the check you require:
do{
VARIABLE = JOptionPane.showInputDialog(null,"X = ").getClass().getName();
}while(!(VARIABLE.equals("java.lang.Integer"));

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