How to Parse static level variable from the JAVA file? - java

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...")

Related

School Java Escape Room Program

I am writing an escape room project for school which has messages such as a greeting, a win message, a loss message, etc. I stored these messages in a text file and then I read the file and store each line into one ArrayList and to access each line by their respective getter method and I use the .get function with their index value. I'm wondering if there is a way to avoid hardcoding the index numbers and on top of that is there a way I can just read the file when the program is run instead of having to make an instance of the class and then for example doing foo.readFile();
import java.io.File;
import java.util.Scanner;
import java.io.FileNotFoundException;
import java.util.ArrayList;
//package Stage;
public class EscapeRoom{
ArrayList<String> Messages;
String fileName;
private boolean win = false;
public void readFile() throws FileNotFoundException {
Messages = new ArrayList<String>();
fileName = "test.txt";
File file = new File(fileName);
Scanner scanner = new Scanner(file);
while(scanner.hasNextLine()){
Messages.add(scanner.nextLine());
}
scanner.close();
}
public void showGreeting(){
System.out.println(Messages.get(0));
}
public void showDirections(){
System.out.println(Messages.get(1));
}
public void showWin() {
System.out.println(Messages.get(2));
}
public void showLoss() {
System.out.println(Messages.get(3));
}
}
This is exactly what a properties file is for. Here is a file I named prompts.properties:
greeting = "hello, welcome to my game"
win = "you win, yay"
loss = "sorry bro, you lose"
directions = "escape with your life!"
Here is your modified program:
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class EscapeRoom {
Properties prompts = null;
public void readFile() throws IOException {
prompts = new Properties();
prompts.load(new FileInputStream("prompts.properties"));
}
public void showGreeting() {
System.out.println(prompts.get("greeting"));
}
public void showDirections() {
System.out.println(prompts.get("directions"));
}
public void showWin() {
System.out.println(prompts.get("win"));
}
public void showLoss() {
System.out.println(prompts.get("loss"));
}
}
Basically to get a named key-value pair you want something like a map. Properties are really a special sort of map that understands a file of records that have the format <key> = <value>.
Here is the documentation on Properties and if you decide to roll your own you would implement the same basic thing with a Map.

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());
}
}

Java. Reference to method without parameters

I have one problem in understanding of Java 8 associated with reference to methods as a parameter to static methods. There is my code where I can't find how to send a reference to a method which doesn't have any parameters and must be a method for an object of the definite class.
So, I want that the method which I send to static function may be used for the object in the static method.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
interface FuncForPath<T> {
T func(T path);
}
class MethodsForFolder {
public static void printFilesInFolder(Path path, FuncForPath<Path> funcPath) {
Stream<Path> paths = null;
try {
paths = Files.list(path);
} catch (IOException e) {
System.out.println(
"The problems have been appeared during reading folder: " + path.toAbsolutePath().toString());
e.printStackTrace();
}
System.out.println("Files list in folder:" + path.toAbsolutePath().toString());
paths.forEach(p -> funcPath.func(p).toString()); // I don't know to how to write this code to perform
}
}
public class TestRefToIntance {
public static String testWindowsFloder = "C://Logs";
public static void main(String[] args) {
Path path = Paths.get(testWindowsFloder);
// I want that this 2 methods are performed depending on transfered methods
// reference
MethodsForFolder.printFilesInFolder(path, Path::toAbsolutePath);
MethodsForFolder.printFilesInFolder(path, Path::getFileName);
}
}
Try Function<Path, Path> instead of FuncForPath. This will require a method taking a Path parameter and returning a Path. Note that instance methods always have an "invisible" this parameter, hence Path::getFileName matches that signature.
You'd then call it like this: paths.forEach( p -> funcPath.apply( p ).toString() ); (although you're not doing anything with the returned string, so you probably want to call paths.map( f ).map( Path::toString ).collect( someCollector ); instead.
How I understand I have resolved this problem. There is code below.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
interface FuncForPath<T> {
T func(T path);
}
class MethodsForFolder {
public static void printFilesInFolder(Path path, FuncForPath<Path> funcPath) {
Stream<Path> paths = null;
try {
paths = Files.list(path);
} catch (IOException e) {
System.out.println(
"The problems have been appeared during reading folder: " + path.toAbsolutePath().toString());
e.printStackTrace();
}
System.out.println("Files list in folder:" + path.toAbsolutePath().toString());
paths.forEach(p -> System.out.println(funcPath.func(p).toString())); // I don't know to how to write this code to perform
}
}
public class TestRefToIntance {
public static String testWindowsFloder = "C://Logs";
public static void main(String[] args) {
Path path = Paths.get(testWindowsFloder);
// I want that this 2 methods are performed depending on transfered methods
// reference
MethodsForFolder.printFilesInFolder(path, Path::toAbsolutePath);
MethodsForFolder.printFilesInFolder(path, Path::getFileName);
}
}
Also, I have deleted the generic specification in interface description.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
interface FuncForPath { // there is interface without type <T>
Path func(Path path);
}
class MethodsForFolder {
public static void printFilesInFolder(Path path, FuncForPath funcPath) {
Stream<Path> paths = null;
try {
paths = Files.list(path);
} catch (IOException e) {
System.out.println(
"The problems have been appeared during reading folder: " + path.toAbsolutePath().toString());
e.printStackTrace();
}
System.out.println("Files list in folder:" + path.toAbsolutePath().toString());
paths.forEach(p -> System.out.println(funcPath.func(p).toString())); // I don't know to how to write this code
// to perform
}
}
public class TestRefToIntance {
public static String testWindowsFloder = "C://Logs";
public static void main(String[] args) {
Path path = Paths.get(testWindowsFloder);
// I want that this 2 methods are performed depending on transfered methods
// reference
MethodsForFolder.printFilesInFolder(path, Path::toAbsolutePath);
MethodsForFolder.printFilesInFolder(path, Path::getFileName);
}
}

Printing contents from an arraylist

so I'm trying to figure out how to print the actual contents, not memory locations, of my array list
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class hw2redo
{
public static void main(String args[]) throws FileNotFoundException
{
//Scan file for data
GeometricObject g = null;
BufferedReader file = new BufferedReader(new FileReader("file.txt"));
Scanner diskScanner = new Scanner(file);
//Create dynamic array list
ArrayList<GeometricObject> list = new ArrayList<GeometricObject>();
//Scan data and add data to list
while(diskScanner.hasNext())
{
String geolist = diskScanner.nextLine();
g = recreateObject(geolist);
list.add(g);
}
showObjects(list);
}
private static GeometricObject recreateObject(String data)
{
GeometricObject object = new GeometricObject(data);
return object;
}
private static void showObjects(ArrayList<GeometricObject> list)
{
for(GeometricObject o : list)
System.out.println(o);
}
}
class GeometricObject
{
public GeometricObject(String data) {
// TODO Auto-generated constructor stub
}
}
So here is my code. I have tried using the toString() and Arrays.toString() but they dont seem applicable for an arraylist (I tried because they worked on my regular arrays).
The output I'm recieving is
// Output
GeometricObject#55f96302
GeometricObject#3d4eac69
GeometricObject#42a57993
GeometricObject#75b84c92
GeometricObject#6bc7c054
GeometricObject#232204a1
which is good because I'm close, I just need to figure out how to print the actual contents.
The content I'm looking for in my file.txt is
Circle,green,false,4.0
Circle,blue,false,2.0
Circle,blue,true,7.0
Rectangle,orange,true,10.0,6.0
Rectangle,green,false,5.0,11.0
Rectangle,red,true,14.0,12.0
Any help would be much appreciated. Thanks!
You need a toString method in your class:
class GeometricObject
{
private String data;
public GeometricObject(String data) {
this.data = data;
}
#Override
public String toString() {
return data;
}
}
Without the Override, you are using Object.toString(). Object's toString prints out the class name and the hashcode of the object, as you have observed.
System.out.println(o);
When you call System.out.println, That apparently calls the toString() method of your Object. Since you didn't ovveride toString(), it calls the default implementation. Ovveride toString() method to print as you wish.
public class GeometricObject {
....
#Override
public String toString() {
// return string representation of your object.
}
}
To starts with :What is the best standard style for a toString implementation?

Package that calls different classes when given input to?

I have taken all of my classes from my intro to java college in highschool class, and put them into a package called gameChoices. I then made a class that would call these classes when the user asks for them, this is called whichGame. I've imported the classes I want called using import gameChoices."whatever game it is";. How do I call these classes in whichGame? I also have them all as public static main(string [] args), which ones shouldn't have that(I think it's just whichGame that should..)? And what would I put instead? Thanks for helping a newbie out :)
The simplest way to do it is probably to set up a big if/then statement.
if(input.equals("t"))
thisOne.start();
else if(input.equals("a"))
anotherOne.start();
else if(input.equals("y"))
yetAnotherOne.start();
And so on. Might be a pain if you have a lot of classes, or if they start with the same letter.
Not sure exactly what you want to achieve, but if you need to access a class by its name you can try Class.forName() and check for exceptions thrown (particularly, ClassNotFoundException).
Using case-insensitive String equality for the name check, if would allow you to access any existing class of your ClassLoader through reflection.
Edit
Here's your main class:
package test;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
public class Main {
// initializes your map of letter->game class
private static final Map<String, Class<?>> GAMES = new HashMap<String, Class<?>>();
// constant name of main method for your games
private static final String MAIN_METHOD_NAME = "main";
// add your games
static {
GAMES.put("c", Chess.class);
GAMES.put("d", Doom.class);
// TODO moar gamez
}
public static void main(String[] args) {
try {
// prompts the user
System.out.println("Enter the game's name or starting letter: ");
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)
);
// gets the response
String input = br.readLine();
br.close();
// iterates over your games' first letters
for (String gameName : GAMES.keySet()) {
// the input starts with one game's first letter...
if (gameName.startsWith(input.toLowerCase())) {
// gets the class
GAMES.get(gameName)
// gets its main method (typical signature is String[] args)
.getMethod(MAIN_METHOD_NAME, String[].class)
// invokes its main method with no arguments
.invoke((Object) null, (Object) null);
}
}
// handles any disaster
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Now here are two "game" classes:
package test;
public class Chess {
public static void main(String[] args) {
System.out.println("You've chosen Chess!");
}
}
... and...
package test;
public class Doom {
public static void main(String[] args) {
System.out.println("You've chosen Doom!");
}
}
Now set your "Main" class as your... main class.
When you launch the application, it will query you for an initial letter.
If you choose "c" or "d", it will print out: "You've chosen [Chess/Doom]!"
I hope this helps you getting started.

Categories