Is there a plugin or parser for Netbeans that can create a tree structure out of my Java source code(or otherwise let me easily extract things like class names, attributes and methods)?
Edit: I need the names for programming purposes, not just to get them. I need them to be returned to my program at runtime.
If I have this source code(for a game):
class Main {
Terrain terrain;
TradingSystem currentSystem;
City city;
public static void main(String[] args) {
}
}
class Terrain {
}
class City {
House tavern;
}
class TradingSystem {
Bank cityBank;
Trader npc1;
}
then I need a parser than can create something like this
----------Main-------------------
| | |
Terrain City --TradingSystem---
| | |
House Bank Trader
from my source code. I need a path from Main to the branches, like this Main->TradingSystem->Bank, or this Main->City->House.
I need to be able to extract the
Class names
Method names
Attribute names
I need it for a Netbeans plugin I'm creating. Does this exist, free to use/download?
Edit: If there exist something for extracting the class names, attribute names and method names from one and one source file that is a good second option. I can write the additional logic from there.
I have created 3 simple classes:
public class A {
B b;
}
public class B {
C c;
public C getC() {
return c;
}
}
public class C {
}
And another slightly complex:
public class SO {
A a;
B b;
C c;
public static void fooMethod1() {
}
public String fooMethod2() {
return "";
}
private double fooMethod3() {
return 0.0;
}
}
I was able to extract the information above through this recursive code:
public void getData(Map<String, Set<String>> fields, Map<String, Set<String>> methods, Class clazz)
{
if(clazz.isPrimitive())
{
return;
}
for(Method method : clazz.getDeclaredMethods())
{
if(!methods.containsKey(clazz.getName()))
{
Set<String> methodNames = new HashSet<>();
methodNames.add(method.getName());
methods.put(clazz.getName(), methodNames);
}
else
{
methods.get(clazz.getName()).add(method.getName());
}
}
for(Field field : clazz.getDeclaredFields())
{
if(!fields.containsKey(clazz.getName()))
{
Set<String> fieldNames = new HashSet<>();
fieldNames.add(field.getName());
fields.put(clazz.getName(), fieldNames);
}
else
{
fields.get(clazz.getName()).add(field.getName());
}
getData(fields, methods, field.getType());
}
}
I called the code above like so:
SO so = new SO();
Map<String, Set<String>> methods = new HashMap<>();
Map<String, Set<String>> fields = new HashMap<>();
so.getData(fields, methods, SO.class);
And printed the results like so:
for(String str : fields.keySet())
{
System.out.println(str);
for(String fieldName : fields.get(str))
{
System.out.print(fieldName + " ");
}
System.out.println();
}
System.out.println("-------------------------------");
for(String str : methods.keySet())
{
System.out.println(str);
for(String methodName : methods.get(str))
{
System.out.print(methodName + " ");
}
System.out.println();
}
The yielded result was like so:
so.B
c
so.SO
b c a
so.A
b
-------------------------------
so.B
getC
so.SO
fooMethod3 getData fooMethod1 fooMethod2 main
Which should be what you are after.
Related
I have a list of methods within my class. And then want to have input string array, where the user can choose which methods they want to run. We are running expensive insurance calculations. And have over say eg 20 methods. Is there a way to conduct this without do an if check on each? maybe with reflection or interface?
#Override
public void ProductTest(ProductData productData, String[] methodNames) {
public void methodA(ProductData productData){...};
public void methodB(ProductData productData){...};
public void methodC(ProductData productData){...};
public void methodD(ProductData productData){...};
public void methodE(ProductData productData){...};
}
I am willing to change the Array into a different ObjectType if needed, to execute properly. Using SpringBoot, has it has a library of utility classes.
Use a Map<String, Consumer<ProductData>>, not separate method handles. Main reason - reflection is slow and dangerous when given user "input"
Use map.get(input).accept(product) to call it.
https://docs.oracle.com/javase/8/docs/api/index.html?java/util/function/Consumer.html
Example
Map<String, Consumer<ProductData>> map = new HashMap<>();
map.put("print_it", System.out::println);
map.put("print_id", data -> System.out.println(data.id));
map.put("id_to_hex", data -> {
int id = data.getId();
System.out.printf("0x%x%n", id);
});
ProductData data = new ProductData(16);
map.get("print_it").accept(data);
map.get("print_id").accept(data);
map.get("id_to_hex").accept(data);
Outputs
ProductData(id=16)
16
0x10
If you are planning on chaining consumers using andThen, you'd be better having an Optional<ProductData>, and using a Function<ProductData, ProductData> with Optional.map()
One way to do it is via reflection. You can iterate over methods in the class object and look for ones to run by name. Here's some example code--this would print out a list of names the user could type in:
myObject.getClass().getDeclaredMethods().each((method)->System.out.println(method.getName()))
And this is how you would call it once the user had made a selection:
productTest.getDeclaredMethods().each((method)->
if(method.getName().equals(userSelectedName))
method.invoke(productTest, productData)
)
The ONLY advantage to this approach is that you don't have to maintain a second structure (Switch, Map, etc...) and add to it every time you add a new method. A personality quirk makes me unwilling to do that (If adding something one place forces you to update a second, you're doing it wrong), but this doesn't bother everyone as much as it bothers me.
This isn't dangerous or anything, if you don't have a method in the class it can't call it, but if you are relying on users "Typing", I'd suggest listing out the options and allowing a numeric selection--or using reflection to build a map like OneCricketeer's.
I've used this pattern to write a testing language and fixture to test set-top TV boxes, it was super simple to parse a group of strings, map some to methods and other to parameters and have a very flexible, easily extensible testing language.
The method object also has a "getAnnotation()" which can be used to allow more flexible matching in the future.
You can use method invocation.
For example, you can have two methods, first one will loop through your methodNames array and call the second method:
public void callPassedMethods(ProductData productData, String[] methodNames) {
for (String m : methodNames) {
callMethod(productData, m)
}
}
And the second method will actually find a method in your class that matches the string passed and invoke it:
public void callMethod(ProductData productData, String methodName) {
try {
ClassName yourObj = new ClassName(); // Class where your methods are
Method method = yourObj.getClass().getDeclaredMethod(methodName, ProductData.class);
method.invoke(yourObj, productData);
} catch(NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
// handle exceptions
}
}
Or, you can always use the good old switch statement:
for (String m : methodNames) {
switch (m) {
case "methodA":
methodA();
break;
case "methodB":
methodB();
break;
// ... continue with as many cases as you need
}
}
If you go with the reflection route, you don't really want to expose your method names to the end users. They might not be end user-friendly, and if they are, there is no reason for users to know this information and there might be methods, which are not supposed to be invoked by users. I would use custom annotations to build more flexible matching.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface UserChoice {
String userFriendlyOption();
int optionNumber();
}
optionNumber will be used for matching the method to invoke, userFriendlyOption is some user friendly text.
Annotate only the methods, supposed to be used by users.
#RequiredArgsConstructor
public class ProductData {
private final double data;
#UserChoice(userFriendlyOption = "see result for option a", optionNumber = 1)
public void methodA() {
System.out.println(data + 1);
}
#UserChoice(userFriendlyOption = "see result for option b", optionNumber = 2)
public void methodB() {
System.out.println(data + 2);
}
#UserChoice(userFriendlyOption = "see result for option c", optionNumber = 3)
public void methodC() {
System.out.println(data);
}
public void methodNotForUser() {
System.out.println("Should not be seen by users");
}
}
Like this methodNotForUser() can't be invoked by end users.
Simplified matcher might look like this.
#RequiredArgsConstructor
public class ProductTester {
private final ProductData data;
private Map<Integer, MethodData> map;
public void showOptions() {
if (this.map == null) {
this.map = new HashMap<>();
for (Method method : this.data.getClass().getMethods()) {
UserChoice userChoice = method.getAnnotation(UserChoice.class);
if (userChoice != null) {
String userRepresentation = userChoice.optionNumber() + " - " + userChoice.userFriendlyOption();
this.map.put(userChoice.optionNumber(), new MethodData(userRepresentation, method));
}
}
}
this.map.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(entry -> System.out.println(entry.getValue().getUserRepresentation()));
}
public void showOptionResult(int choice) {
MethodData methodData = this.map.get(choice);
if (methodData == null) {
System.out.println("Invalid choice");
return;
}
System.out.println("Result");
try {
methodData.getMethod().invoke(this.data);
} catch (IllegalAccessException | InvocationTargetException ignore) {
//should not happen
}
}
}
MethodData is simple pojo with the sole purpose to not recalculate user representation.
#RequiredArgsConstructor
#Getter
public class MethodData {
private final String userRepresentation;
private final Method method;
}
Short main to illustrate the idea and play around:
public class Temp {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Write initial value");
double data = scanner.nextDouble();
ProductData myData = new ProductData(data);
ProductTester tester = new ProductTester(myData);
tester.showOptions();
System.out.println("Write option number");
int userChoice = scanner.nextInt();
tester.showOptionResult(userChoice);
}
}
Im going to go straight to the point.
I got 3 classes. Person, Professor and Student. (Persona, Profesor, Alumno).
Both professor and student extends from Person. But Person can also be instantiated, because it's not abstract.
I have 50 persons, randomly generated on a list. It can be any kind, person professor or student.
I want to separate them each into a different list.
At the moment, I did this:
for(Persona persona : personas) {
if(persona instanceof Profesor) {
profesores.add((Profesor) persona);
}
else if(persona instanceof Alumno) {
alumnos.add((Alumno) persona);
}
else {
nuevasPersonas.add(persona);
}
}
profesores is a list of Professor
alumnos is a list of Students
nuevasPersonas is a list of Persons
Which works perfect. But I was told not to use instanceof, so I don't get used to it.
Any ideas on how to separate them into lists, without the use of instanceof?
Thanks.
I would use instanceof, why wouldn't you want to get used to it?
Anyway, an alternative could be having a variable type (with getter, but no setter), in Person (=0), and override it to 1 and 2 in Professor and Student.
Then,you would test the variable instead of using instanceof.
Perhaps your teacher wants you to create an overriden method which answers the question isStudent or isProfessor?
However, since this gives us no extra information that is not already available via the instanceof operator, this is a contrived example where adding these redundant methods is not really a great design decision. Unfortunately in beginner classes you will sometimes encounter such contrived examples which are overly simplified for the purpose of teaching a particular language concept.
You can overload an "add" method with each of the object types - something like the following code.
The main method just adds instances of three different Objects to the ObjectSplitter class - it separates them out in to different Collections
public class ObjectSplitter {
public static void main(String ... args){
ObjectSplitter d = new ObjectSplitter();
d.addToCollection(new Object1());
d.addToCollection(new Object1());
d.addToCollection(new Object2());
d.addToCollection(new Object1());
d.addToCollection(new Object1());
d.addToCollection(new Object1());
d.addToCollection(new Object2());
d.addToCollection(new Object3());
d.addToCollection(new Object1());
System.out.println("Num Ob1s : " + d.getOb1sSize());
System.out.println("Num Ob2s : " + d.getOb2sSize());
System.out.println("Num Ob3s : " + d.getOb3sSize());
}
private List<Object1> ob1s = new ArrayList<>();
private List<Object2> ob2s = new ArrayList<>();
private List<Object3> ob3s = new ArrayList<>();
void addToCollection(Object1 o){
ob1s.add(o);
}
void addToCollection(Object2 o){
ob2s.add(o);
}
void addToCollection(Object3 o){
ob3s.add(o);
}
int getOb1sSize(){
return ob1s.size();
}
int getOb2sSize(){
return ob2s.size();
}
int getOb3sSize(){
return ob3s.size();
}
static class Object1 {
}
static class Object2 extends Object1 {
}
static class Object3 extends Object2 {
}
}
also you can use getClass().getSimpleName() as below:
public static void main (String[] args) throws java.lang.Exception
{
List<Test1> list = new ArrayList<>(2);
Test1 o1 = new Test1();
list.add(o1);
Test2 o2 = new Test2();
list.add(o2);
for (Test1 test : list) {
System.out.println(test.getClass().getSimpleName());
}
}
static class Test1{
}
static class Test2 extends Test1{
}
in the for loop you can have a if condition as like as below code to do your job:
for (Test1 test : list) {
String className = test.getClass().getSimpleName();
if(className.equals("Test1")) {
System.out.println("Test1");
} else if(className.equals("Test2")) {
System.out.println("Test2");
}
System.out.println();
}
another solution according to overriding methods is:
public static void main (String[] args) throws java.lang.Exception
{
List<Test1> list = new ArrayList<>(2);
Test1 o1 = new Test1();
list.add(o1);
Test2 o2 = new Test2();
list.add(o2);
for (Test1 test : list) {
test.addToMyTypeList();
}
for(Test1 test : Test1.list) {
System.out.println(test.getClass().getSimpleName());
}
for(Test1 test : Test1.list) {
System.out.println(test.getClass().getSimpleName());
}
}
static class Test1{
public static List<Test1> list = new ArrayList<>();
public void addToMyTypeList() {
String className = test.getClass().getSimpleName();
if(className.equals("Test1")) {
Test1.list.add(this);
}
}
}
static class Test2 extends Test1{
public static List<Test1> list = new ArrayList<>();
#Override
public void addToMyTypeList() {
String className = test.getClass().getSimpleName();
if(className.equals("Test2")) {
Test2.list.add(this);
}
}
}
I have get and set class :
public static class Structure{
private String YOne = null;
private String YTwo = null;
public String getYOne() {
return YOne;
}
public void setYOne(String YOne) {
this.YOne = YOne;
}
public String getYTwo() {
return YTwo;
}
public void setYTwo(String YTwo) {
this.YTwo = YTwo;
}
}
Then I fill that in my class :
Structure.setYOne("my value");
Structure.setYTwo("my value");
How I can empty all of them ?
Notice : I don't like empty that one by one .
You can implement a method in your Structure class that sets all the fields to null using Reflection:
public void clearFields() throws IllegalArgumentException, IllegalAccessException {
Field[] properties = this.getClass().getDeclaredFields();
for (Field f : properties) {
f.setAccessible(true);
f.set(this, null);
}
}
Rebuild your object, no other choice if you don't want to do it one by one
Structure s = new Structure();
// YOne and YTwo are null
s.setYOne("my value");
s.setYTwo("my value");
// YOne and YTwo are not null;
s = new Structure();
// YOne and YTwo are null again
edit : be careful though, it could mess up your reference if your object is used in another class.
You are lacking basic class and object concept here. You need to create an array of objects of Structure class. The use a foor loop to loop through all the objects and set methods.
for(Structure x : your_array_of_Structures ){
x.set(whatever);
x.get(whatever);
}
Go to http://www.tutorialspoint.com/java/java_loop_control.htm where you can get more tutorials on how to do these basic things in Java.
String activityState = "resume";
DebugLog(activityState)
void DebugLog(String obj1) {}
How to make the DebugLog to print like this:
activityState : resume
I used to write many print statement as logs at many places while debugging. I will write statements like
System.out.println("activityState : " + activityState);
I want a method to print the variable name and variable value. In C++, it can be done like the below:
#define dbg(x) cout<< #x <<" --> " << x << endl ;
Is there any way to do this?
Thanks in advance.
There's no direct solution to get the variable name.
However, in a context where you have many fields and don't want to manually print their state, you can use reflection.
Here's a quick example:
class MyPojo {
public static void main(String[] args) {
System.out.println(new MyPojo());
}
int i = 1;
String s = "foo";
#Override
public String toString() {
StringBuilder result = new StringBuilder();
for (Field f: getClass().getDeclaredFields()) {
try {
result
.append(f.getName())
.append(" : ")
.append(f.get(this))
.append(System.getProperty("line.separator"));
}
catch (IllegalStateException ise) {
result
.append(f.getName())
.append(" : ")
.append("[cannot retrieve value]")
.append(System.getProperty("line.separator"));
}
// nope
catch (IllegalAccessException iae) {}
}
return result.toString();
}
}
Output
i : 1
s : foo
You can use java Reflection to get the variable name and the value. Here's an example code;
public class Example{
String activityState = "resume";
public static void main(String[] args) {
Example example = new Example();
Class<?> c = example.getClass();
Field field = c.getDeclaredField("activityState");
System.out.println(field.getName());
System.out.println(field.get(example));
}
}
Since this is for debugging you could use instrumentation with aspectj, your code remains clean from the the debugging output statements and you can waeve the aspect as needed.
Define a set(FieldPattern) point cut to catch all field assignements (join points)
public aspect TestAssignmentAspect {
pointcut assigmentPointCut() : set(* *);
after() : assigmentPointCut() {
System.out.printf("%s = %s%n", thisJoinPoint.getSignature().getName(),
String.valueOf(Arrays.toString(thisJoinPoint.getArgs())));
}
}
Here is Test class
public class Test {
public static String activityState = "stopped";
public static void main(String[] args) {
activityState = "start";
doSomething();
activityState = "pause";
doSomeOtherthing();
activityState = "resume";
System.out.printf("the end!%n");
}
private static void doSomeOtherthing() {
System.out.printf("doing some other thing...%n");
}
private static void doSomething() {
System.out.printf("doing something...%n");
}
}
If you run this example with the aspect weaved the output will be
activityState = [stopped]
activityState = [start]
doing something...
activityState = [pause]
doing some other thing...
activityState = [resume]
the end!
Explanation
pointcut assigmentPointCut() : set(* *);
set point cut to catch assignments, the point joins, to any variable with any name, could also in the example be
pointcut assigmentPointCut() : set(String activityState);
The advice, the desired behavior when the given point cut matches
after() : assigmentPointCut() { ... }
Informations about the point join can be accessed using the special reference thisJoinPoint.
I have enum like:
public enum Enum2
{
ONE,TWO,THREE;
}
I can list all values like:
public static void main(String... args)
{
for (Enum2 e : Enum2.values())
{
System.out.println(e);
}
}
Is it possible list values if I have only string name of Enum?
String enum_name="Enum2";
E.g. if in some logic like:
if (a>b)
{
enum_name="EnumA";
}
else
{
enum_name="EnumB";
}
And after I receive string name of enum - I can list all values.
Class<?> enumClazz = Class.forName("com.mycompany.Enum2");
for (Enum<?> e : ((Class<? extends Enum<?>>)enumClazz).getEnumConstants()) {
System.out.println(e.name()); // The variable "e" would be Enum2.ONE, etc
}
Thank you #Harry for helping me get this right.
Your question is not much clear to be but this is what you may want to do
Class<?> cls = Class.forName("EnumName");
if (cls.isEnum()) {
Field[] flds = cls.getDeclaredFields();
//-- your logic for fields.
}
You can use: Class.getEnumConstants(). For more see this.
yes, with
Enum2.EnumA.toString();