I would like to retrieve all variable names in all methods of a java file. Example Like a Person.java contains
class Person {
private String firstName;
private String lastName;
public static void main() {
String test = "test";
Person p1 = new Person();
p1.setName("John");
}
public void setName(String name) {
this.firstName = name;
}
}
i would like to be able to print out all variables declared. I have tried using javaparser to retrieve them.
However, i can only retrieve variables declared in the class which is
firstName
lastName
I want to be able to retrieve all variables declared in main method as well
firstName
lastName
test
My javaparser method is
public static void getVariables(String inputFilePath) {
try {
CompilationUnit cu = StaticJavaParser.parse(new File(inputFilePath));
cu.findAll(FieldDeclaration.class).forEach(field -> {
field.getVariables().forEach(variable -> {
System.out.println(variable.getName());
variable.getInitializer().ifPresent(initValue ->
System.out.println(initValue.toString()));
});
});
} catch (FileNotFoundException fe) {
System.out.println(fe.getMessage());
} catch (IOException e){
System.out.println(e.getMessage());
}
}
Solved
As following Eugene's suggestion, i am able to retrieve all variables now
public static void getVariables(String inputFilePath) {
try {
CompilationUnit cu = StaticJavaParser.parse(new File(inputFilePath));
cu.findAll(VariableDeclarator.class).forEach(variable -> {
System.out.println(variable);
});
} catch (FileNotFoundException fe) {
} catch (IOException e) {
}
}
You are passing FieldDeclaration.class into CompilationUnit's findAll() method. So, as asked, it gets you all declared fields.
If you want to list all declared variables, use VariableDeclarator.class from the same package – it will get you all of those, including the ones declared as fields.
Related
In MainActivity.java, I have the following
classofmethods new1 = new classofmethods();
static getset GS = new GS();
.....
code .....
settle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String keyword1 = nc.methodName(String, String, int);
GS.setkeyword(keyword1);
try {
//Method 1 makes an API call...Trying to set an //endpoint but the URL prints out as ....keyword=null;
new1.method1();
new1.method2();
new1.method3();
new1.method4();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
GS
String keyword = null;
public String getkeyword() {
return keyword;
}
public void setkeyword(String keyword) {
this.keyword = keyword;
}
My problem is that the onClick executes my desired code, however it will not set the keyword.
In the GS class, I declared keyword as "public String keyword = null;"
The API when executed in method1() returns null.
I guess it is a timing issue? I have looked at other threads but no solutions. I have another activity that adjust users settings and those values are passed through the API correctly.
Edit: this is why stack overflow has post quality guidelines. I failed to provide enough info.
In my classofmethods:
keyword was declared like: public String keyword = GS.getkeyword();
endpoint was specified like: &keyword=" + keyword
fix was: &keyword=" + MainActivity.GS.getkeyword()
Use this
private String keywword;
public String getkeyword() {
return keyword;
}
public void setkeyword(String keyword) {
this.keyword = keyword;
}
Let's say I have a class named Person and its constructor had variables like name, age, hairColor and so on. If I had a function that receives a string that should match one of the class's variables, how could I check if that class actually had that variable and how could I go about modifying it? For example:
public class Person {
public String name;
public int age;
public String hairColor;
public Person() {
name = "Bryce";
age = 21;
hairColor = "brown";
}
public void changeHairColor(String variable, String color) {
if (/*this class contains the variable passed as an argument to this method*/) {
// Person[variable] = color
}
}
}
I'm a python dev, mostly, so the method changeHairColor has some pseudo-python in it. I want to be able to edit the variable in a similar way you could edit variables inside of dictionaries with Python:
person = {
"name": "Bryce",
"age": 21,
"hairColor": "brown"
}
def changeHairColor(variable, color):
person[variable] = color
If that is at all possible.
The only way to do it in Java is to use Java Reflection API:
public class Test {
public String name;
public int age;
public String hairColor;
public void setProperty(String property, Object value) {
try {
Field declaredField = this.getClass().getDeclaredField(property);
switch (declaredField.getAnnotatedType().getType().getTypeName()) {
case "java.lang.String":
declaredField.set(this, value);
break;
// handle other types
}
} catch (NoSuchFieldException e) {
// handle exception
} catch (IllegalAccessException e) {
// handle exception
}
}
public static void main(String[] args) {
Test test = new Test();
test.setProperty("name", "Bob");
System.out.println(test.name);
}
}
I would not solve this with reflection. If your PlayerCharacter has an enumerable set of attributes, I would model these as a Java enum and store the attribute values within the PlayerCharacter object in an EnumMap:
import java.util.EnumMap;
public class PlayerCharacter {
public enum Attribute {
AGILITY,
DEXTERITY,
/* etc ...*/
VITALITY
}
private EnumMap<Attribute, Integer> attributes = new EnumMap<>(Attribute.class);
public PlayerCharacter() {
// initialize each attribute with a default value (0 in this example)
for (Attribute a : Attribute.values()) {
attributes.put(a, new Integer(0));
}
}
public int getValue(Attribute attribute) {
return attributes.get(attribute);
}
public void levelUp(Attribute attribute, int amount) {
attributes.put(attribute, attributes.get(attribute) + amount);
}
}
The biggest benefit of using an enum instead of plain old String (+reflection), is that this way you get compile-time type safety for the code that's using your PlayerCharacter.
Using Reflection API, you can access the methods and properties on an object at run time. The other answer describes its usage. But I don't recommend reflections for your problem. How about the following:
public void changeHairColor(String variable, String color) {
if("name".equalsIgnoreCase(variable))
this.name = color;
else if("age".equalsIgnoreCase(variable))
this.age = Integer.parseInt(color);
else if("color".equalsIgnoreCase(variable))
this.color = color;
else
throw new Exception ("error - property not available");
}
}
Note, your existing method name 'changeHairColor' doesn't make sense in the context. It should be someething like 'changeProperty' because you are not just changing the 'color', you are changing any available property with this method.
I'm trying to read a csv and storing the records in an ArrayList.
Since I know the no. of records in the csv file I'm specifying the size i.e. 600 when creating the object.
I want the program to be able to read files of unknown no. of records.
How do I make it dynamic.
Here's the working code for the file with 600 records.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.io.*;
public class BankRecords extends Client{
//Create objects for processing data
//private static int count;
static BankRecords[] obj=new BankRecords[600];
static List<List<String>> array = new ArrayList<List<String>>();
#Override
void readData() {
// TODO Auto-generated method stub
String line=" ";
//int i=0;
//try with resources statement
try(BufferedReader br = new BufferedReader(new FileReader("bank-Detail.csv"))){
while((line=br.readLine()) != null) //read from file
{
array.add(Arrays.asList(line.split(",")));
//check data
//count++;
//System.out.println(array.get(i++));
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
processData();
}
#Override
void processData() {
// TODO Auto-generated method stub
int idx=0;
for(List<String> bankData: array)
{
obj[idx]= new BankRecords();
obj[idx].setId(bankData.get(0));
obj[idx].setAge(Integer.parseInt(bankData.get(1)));
obj[idx].setSex(bankData.get(2));
obj[idx].setRegion(bankData.get(3));
obj[idx].setIncome(Double.parseDouble(bankData.get(4)));
obj[idx].setMarried(bankData.get(5));
obj[idx].setChild(Integer.parseInt(bankData.get(6)));
obj[idx].setCar(bankData.get(7));
obj[idx].setSact(bankData.get(8));
obj[idx].setCact(bankData.get(9));
obj[idx].setMort(bankData.get(10));
obj[idx].setPep(bankData.get(11));
idx++;
//System.out.println(obj[idx].getId());
}
printData();
}
#Override
void printData() {
//Printing First 25 ID, age, sex, region, income and mortgage
System.out.println("ID\t\tAGE\t\tSEX\t\tREGION\t\tINCOME\t\tMORTGAGE\n");
for(int i=0;i<25;i++){
String s=String.format("%s\t\t%s\t\t%s\t\t%-10s\t%8.2f\t%2s", obj[i].getId(),obj[i].getAge(),obj[i].getSex(),obj[i].getRegion(),obj[i].getIncome(),obj[i].getMort());
System.out.println(s);
}
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
public double getIncome() {
return income;
}
public void setIncome(double income) {
this.income = income;
}
public String isMarried() {
return married;
}
public void setMarried(String married) {
this.married = married;
}
public int getChild() {
return child;
}
public void setChild(int child) {
this.child = child;
}
public String getCar() {
return car;
}
public void setCar(String car) {
this.car = car;
}
public String getSact() {
return sact;
}
public void setSact(String sact) {
this.sact = sact;
}
public String getCact() {
return cact;
}
public void setCact(String cact) {
this.cact = cact;
}
public String getMort() {
return mort;
}
public void setMort(String mort) {
this.mort = mort;
}
public String getPep() {
return pep;
}
public void setPep(String pep) {
this.pep = pep;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
BankRecords bnk= new BankRecords();
bnk.readData();
}
}
ArrayList can the elements dynamically, so it is not required to know the size in advance.
However, for the BankRecords array, do not initialize it with 600 initially. Instead do something like this:
static BankRecords[] obj = null;
static List<List<String>> array = new ArrayList<List<String>>();
void processData() {
// TODO Auto-generated method stub
obj=new BankRecords[array.size()];
// TODO do your work here
}
You do not have to know the number of records beforehand in order to use an ArrayList. You can specify a default size in the constructor, however it is smart enough to expand itself if you add more records than this.
You are almost there, but for some strange reasons you are using Lists in places where you already have an array; yet on the other side, you are using an array where a List would be a much better fit.
You can rework your code as follows:
// TODO Auto-generated method stub
HINT: those TODOs are generated by your IDE. The idea is that you delete them as soon as you have some real content instead. Keeping them means leaving garbage in your source code. Anything that doesn't add real value to your source code: remove it. Always. Immediately!
String line=" ";
List<Bankrecord> records = new ArrayList<>();
//int i=0; ... again: unused code --- remove that!
try(BufferedReader br = new BufferedReader(new FileReader("bank-Detail.csv"))){
while((line=br.readLine()) != null) //read from file
{
String[] lineData = line.split(",");
BankRecord recordForNewLine = buildRecordFrom(lineData);
records.add(recordForNewLine);
} ...
And then you could rework your processData into something like:
private BankRecord buildRecordFrom(String[] lineData) {
BankRecord newRecord = new BankRecords();
newRecord.setId(lineData[0];
...
return newRecord;
}
And things that you should really consider changing, too:
Building your bank records by simply assuming that column contains a valid ID, and the next column contains a valid xyz ... is a bad idea.
Instead, you should be validating all your input: you should check that each array you gain from split has **exactly the expected length. And then have to validate that each value from that array has the expected "content"
Then, from a modelling perspective: you have a ton of setters on your Bankrecord class. But that is simply wrong! In real life, when some "record" is created, then its essential properties (such as its ID) can't be changed after creation!
Instead, you should make sure that such properties in your class can't be changed after the object has been created. The way to go here: Builder pattern!
Finally: my code above is meant as "inspiration point" to get you going. Dont blindly copy/paste it; there might be various typos in - just read it until you get what (and why) it is doing (what it is doing)!
Then: I hope you understand that real CSV parsing is much more complicated than splitting around "," (for example: strings in CSV data can contain ',' too; and then your simple split would rip up that string!)
If you are serious about parsing real-world-other-people CSV input, then you better look into using existing libraries to do this for you. Writing a correct CSV parser is hard work (and not very rewarding; since that means re-inventing a complicated wheel for no good reason)!
public class PropertyDemo {
private static InputStream in = PropertyDemo.class.getClassLoader().getResourceAsStream("address.properties");
public void test() {
try {
// InputStream in = PropertyDemo.class.getClassLoader().getResourceAsStream("address.properties");
Properties pro = new Properties();
pro.load(in);
String address = pro.getProperty("returnInfoRegister");
System.out.println(address);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new PropertyDemo().test();
new PropertyDemo().test();
}}
In above code the first run will return correct value but the second run return null value I don't know why ,but when I change "in" variable to non static (I mean a local variable) things goes right but why?
When you move through the stream reading it, you are at the end of it. Using this as a static, saves that state (as it is the same variable in both class instances you have declared in main). So the next time you use it, it is already at the end of the stream. When you declare it as non-static, it is a new instance for each class instance and you are good.
But there really is no reason to declare this as a class level variable. Your inner variable is much better. You should also consider closing the stream at the end.
public class PropertyDemo {
//private static InputStream in = PropertyDemo.class.getClassLoader().getResourceAsStream("address.properties");
public void test() {
InputStream in = null;
try {
in = PropertyDemo.class.getClassLoader().getResourceAsStream("address.properties");
Properties pro = new Properties();
pro.load(in);
String address = pro.getProperty("returnInfoRegister");
System.out.println(address);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {in.close();} catch (Exception e) {}
}
}
}
public static void main(String[] args) {
new PropertyDemo().test();
new PropertyDemo().test();
}
}
I have read the source code and stored it's contents in a String like this:-
String s="the code of the source file i am reading";
I have tried few times
String s="source code";
String[] lines=s.split("\n");//split my source code into lines
After that i don't know how to find identifiers line by line
You need Java Reflection for this read more here,
public class ReflectFoo2Class {
public ReflectFoo2Class(){
Foo2 f = new Foo2();
Field[] field;
try {
field = f.getClass().getFields();
for(Field fa: field){
System.out.println(fa.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[]args){
new ReflectFoo2Class();
}
}
class Foo2 {
public String v = "";
public String v1 = "";
public String v2 = "";
public void print() {
System.out.println("abc");
}
}